epiworld  0.8.2
epiworld.hpp
1 #include <vector>
2 #include <functional>
3 #include <memory>
4 #include <stdexcept>
5 #include <random>
6 #include <fstream>
7 #include <string>
8 #include <map>
9 #include <unordered_map>
10 #include <chrono>
11 #include <climits>
12 #include <cstdint>
13 #include <algorithm>
14 #include <regex>
15 #include <sstream>
16 #include <iomanip>
17 #include <set>
18 #include <type_traits>
19 #include <cassert>
20 #ifdef EPI_DEBUG_VIRUS
21 #include <atomic>
22 #endif
23 
24 #ifndef EPIWORLD_HPP
25 #define EPIWORLD_HPP
26 
27 /* Versioning */
28 #define EPIWORLD_VERSION_MAJOR 0
29 #define EPIWORLD_VERSION_MINOR 10
30 #define EPIWORLD_VERSION_PATCH 0
31 
32 static const int epiworld_version_major = EPIWORLD_VERSION_MAJOR;
33 static const int epiworld_version_minor = EPIWORLD_VERSION_MINOR;
34 static const int epiworld_version_patch = EPIWORLD_VERSION_PATCH;
35 
36 namespace epiworld {
37 
38 /*//////////////////////////////////////////////////////////////////////////////
40 
41  Start of -include/epiworld/config.hpp-
42 
45 
46 
47 #ifndef EPIWORLD_CONFIG_HPP
48 #define EPIWORLD_CONFIG_HPP
49 
50 #ifndef printf_epiworld
51  #define printf_epiworld fflush(stdout);printf
52 #endif
53 
54 // In case the user has a way to stop the program
55 // This is called during `run_multiple()` and it is
56 // passed the simulation number.
57 #ifndef EPI_CHECK_USER_INTERRUPT
58  #define EPI_CHECK_USER_INTERRUPT(a)
59 #endif
60 
61 #ifndef EPIWORLD_MAXNEIGHBORS
62  #define EPIWORLD_MAXNEIGHBORS 1048576
63 #endif
64 
65 #if defined(_OPENMP) || defined(__OPENMP)
66  #include <omp.h>
67 // #else
68 // #define omp_get_thread_num() 0
69 // #define omp_set_num_threads() 1
70 #endif
71 
72 #ifndef epiworld_double
73  #define epiworld_double float
74 #endif
75 
76 #ifndef epiworld_fast_int
77  #define epiworld_fast_int int
78 #endif
79 
80 #ifndef epiworld_fast_uint
81  #define epiworld_fast_uint unsigned long long int
82 #endif
83 
84 #define EPI_DEFAULT_TSEQ int
85 
86 #ifndef EPI_MAX_TRACKING
87  #define EPI_MAX_TRACKING 200
88 #endif
89 
90 template<typename TSeq = EPI_DEFAULT_TSEQ>
91 class Model;
92 
93 template<typename TSeq = EPI_DEFAULT_TSEQ>
94 class Agent;
95 
96 template<typename TSeq = EPI_DEFAULT_TSEQ>
97 class PersonTools;
98 
99 template<typename TSeq = EPI_DEFAULT_TSEQ>
100 class Virus;
101 
102 template<typename TSeq = EPI_DEFAULT_TSEQ>
103 class Viruses;
104 
105 template<typename TSeq = EPI_DEFAULT_TSEQ>
106 class Viruses_const;
107 
108 template<typename TSeq = EPI_DEFAULT_TSEQ>
109 class Tool;
110 
111 template<typename TSeq = EPI_DEFAULT_TSEQ>
112 class Tools;
113 
114 template<typename TSeq = EPI_DEFAULT_TSEQ>
115 class Tools_const;
116 
117 template<typename TSeq = EPI_DEFAULT_TSEQ>
118 class Entity;
119 
120 template<typename TSeq = EPI_DEFAULT_TSEQ>
121 using VirusPtr = std::shared_ptr< Virus< TSeq > >;
122 
123 template<typename TSeq = EPI_DEFAULT_TSEQ>
124 using ToolPtr = std::shared_ptr< Tool< TSeq > >;
125 
126 template<typename TSeq = EPI_DEFAULT_TSEQ>
127 using ToolFun = std::function<epiworld_double(Tool<TSeq>&,Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
128 
129 template<typename TSeq = EPI_DEFAULT_TSEQ>
130 using MixerFun = std::function<epiworld_double(Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
131 
132 template<typename TSeq = EPI_DEFAULT_TSEQ>
133 using MutFun = std::function<bool(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
134 
135 template<typename TSeq = EPI_DEFAULT_TSEQ>
136 using PostRecoveryFun = std::function<void(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
137 
138 template<typename TSeq = EPI_DEFAULT_TSEQ>
139 using VirusFun = std::function<epiworld_double(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
140 
141 template<typename TSeq = EPI_DEFAULT_TSEQ>
142 using UpdateFun = std::function<void(Agent<TSeq>*,Model<TSeq>*)>;
143 
144 template<typename TSeq = EPI_DEFAULT_TSEQ>
145 using GlobalFun = std::function<void(Model<TSeq>*)>;
146 
147 template<typename TSeq>
148 struct Event;
149 
150 template<typename TSeq = EPI_DEFAULT_TSEQ>
151 using EventFun = std::function<void(Event<TSeq>&,Model<TSeq>*)>;
152 
156 template<typename TSeq = EPI_DEFAULT_TSEQ>
157 using VirusToAgentFun = std::function<void(Virus<TSeq>&,Model<TSeq>*)>;
158 
162 template<typename TSeq = EPI_DEFAULT_TSEQ>
163 using ToolToAgentFun = std::function<void(Tool<TSeq>&,Model<TSeq>*)>;
164 
168 template<typename TSeq = EPI_DEFAULT_TSEQ>
169 using EntityToAgentFun = std::function<void(Entity<TSeq>&,Model<TSeq>*)>;
170 
176 template<typename TSeq = EPI_DEFAULT_TSEQ>
177 struct Event {
178  Agent<TSeq> * agent;
179  VirusPtr<TSeq> virus;
180  ToolPtr<TSeq> tool;
181  Entity<TSeq> * entity;
182  epiworld_fast_int new_state;
183  epiworld_fast_int queue;
184  EventFun<TSeq> call;
185  int idx_agent;
186  int idx_object;
187 public:
204  Event(
205  Agent<TSeq> * agent_,
206  VirusPtr<TSeq> & virus_,
207  ToolPtr<TSeq> & tool_,
208  Entity<TSeq> * entity_,
209  epiworld_fast_int new_state_,
210  epiworld_fast_int queue_,
211  EventFun<TSeq> & call_,
212  int idx_agent_,
213  int idx_object_
214  ) : agent(agent_), virus(virus_), tool(tool_), entity(entity_),
215  new_state(new_state_),
216  queue(queue_), call(call_), idx_agent(idx_agent_), idx_object(idx_object_) {
217  return;
218  };
219 };
220 
228 #ifndef DEFAULT_TOOL_CONTAGION_REDUCTION
229  #define DEFAULT_TOOL_CONTAGION_REDUCTION 0.0
230 #endif
231 
232 #ifndef DEFAULT_TOOL_TRANSMISSION_REDUCTION
233  #define DEFAULT_TOOL_TRANSMISSION_REDUCTION 0.0
234 #endif
235 
236 #ifndef DEFAULT_TOOL_RECOVERY_ENHANCER
237  #define DEFAULT_TOOL_RECOVERY_ENHANCER 0.0
238 #endif
239 
240 #ifndef DEFAULT_TOOL_DEATH_REDUCTION
241  #define DEFAULT_TOOL_DEATH_REDUCTION 0.0
242 #endif
243 
244 #ifndef EPI_DEFAULT_VIRUS_PROB_INFECTION
245  #define EPI_DEFAULT_VIRUS_PROB_INFECTION 1.0
246 #endif
247 
248 #ifndef EPI_DEFAULT_VIRUS_PROB_RECOVERY
249  #define EPI_DEFAULT_VIRUS_PROB_RECOVERY 0.1428
250 #endif
251 
252 #ifndef EPI_DEFAULT_VIRUS_PROB_DEATH
253  #define EPI_DEFAULT_VIRUS_PROB_DEATH 0.0
254 #endif
255 
256 #ifndef EPI_DEFAULT_INCUBATION_DAYS
257  #define EPI_DEFAULT_INCUBATION_DAYS 7.0
258 #endif
260 
261 #ifdef EPI_DEBUG
262  #define EPI_DEBUG_PRINTF printf_epiworld
263 
264  #define EPI_DEBUG_ERROR(etype, msg) \
265  (etype)("[[epi-debug]] (error) " + std::string(msg));
266 
267  #define EPI_DEBUG_NOTIFY_ACTIVE() \
268  EPI_DEBUG_PRINTF("DEBUGGING ON (compiled with EPI_DEBUG defined)%s\n", "");
269 
270  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect) \
271  for (auto & v : vect) \
272  if (static_cast<double>(v) < 0.0) \
273  throw EPI_DEBUG_ERROR(std::logic_error, "A negative value not allowed.");
274 
275  #define EPI_DEBUG_SUM_DBL(vect, num) \
276  double _epi_debug_sum = 0.0; \
277  for (auto & v : vect) \
278  { \
279  _epi_debug_sum += static_cast<double>(v);\
280  if (_epi_debug_sum > static_cast<double>(num)) \
281  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
282  }
283 
284  #define EPI_DEBUG_SUM_INT(vect, num) \
285  int _epi_debug_sum = 0; \
286  for (auto & v : vect) \
287  { \
288  _epi_debug_sum += static_cast<int>(v);\
289  if (_epi_debug_sum > static_cast<int>(num)) \
290  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
291  }
292 
293  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c) \
294  if (a.size() != b.size()) {\
295  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
296  EPI_DEBUG_PRINTF("Size of vector a: %lu\n", (a).size());\
297  EPI_DEBUG_PRINTF("Size of vector b: %lu\n", (b).size());\
298  throw EPI_DEBUG_ERROR(std::length_error, "The vectors do not match size."); \
299  }\
300  for (int _i = 0; _i < static_cast<int>(a.size()); ++_i) \
301  if (a[_i] != b[_i]) {\
302  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
303  EPI_DEBUG_PRINTF("Iterating the last 5 values%s:\n", ""); \
304  for (int _j = std::max(0, static_cast<int>(_i) - 4); _j <= _i; ++_j) \
305  { \
306  EPI_DEBUG_PRINTF( \
307  "a[%i]: %i; b[%i]: %i\n", \
308  _j, \
309  static_cast<int>(a[_j]), \
310  _j, static_cast<int>(b[_j])); \
311  } \
312  throw EPI_DEBUG_ERROR(std::logic_error, "The vectors do not match."); \
313  }
314 
315  #define EPI_DEBUG_FAIL_AT_TRUE(a,b) \
316  if (a) \
317  {\
318  throw EPI_DEBUG_ERROR(std::logic_error, b); \
319  }
320 
321  #define epiexception(a) std::logic_error
322 #else
323  #define EPI_DEBUG_PRINTF(fmt, ...)
324  #define EPI_DEBUG_ERROR(fmt, ...)
325  #define EPI_DEBUG_NOTIFY_ACTIVE()
326  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect)
327  #define EPI_DEBUG_SUM_DBL(vect, num)
328  #define EPI_DEBUG_SUM_INT(vect, num)
329  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c)
330  #define EPI_DEBUG_FAIL_AT_TRUE(a, b) \
331  if (a) \
332  return false;
333  #define epiexception(a) a
334 #endif
335 
336 #if defined(EPI_DEBUG_NO_THREAD_ID) || (!defined(__OPENMP) && !defined(_OPENMP))
337  #define EPI_GET_THREAD_ID() 0
338 #else
339  #define EPI_GET_THREAD_ID() omp_get_thread_num()
340 #endif
341 
342 #endif
343 /*//////////////////////////////////////////////////////////////////////////////
345 
346  End of -include/epiworld/config.hpp-
347 
350 
351 
352 /*//////////////////////////////////////////////////////////////////////////////
354 
355  Start of -include/epiworld/epiworld-macros.hpp-
356 
359 
360 
361 #ifndef EPIWORLD_MACROS_HPP
362 #define EPIWORLD_MACROS_HPP
363 
368 #define EPI_NEW_TOOL(fname,tseq) inline epiworld_double \
369 (fname)(\
370  epiworld::Tool< tseq > & t, \
371  epiworld::Agent< tseq > * p, \
372  std::shared_ptr<epiworld::Virus< tseq >> v, \
373  epiworld::Model< tseq > * m\
374  )
375 
380 #define EPI_NEW_TOOL_LAMBDA(funname,tseq) \
381  epiworld::ToolFun<tseq> funname = \
382  [](epiworld::Tool<tseq> & t, \
383  epiworld::Agent<tseq> * p, \
384  std::shared_ptr<epiworld::Virus<tseq>> v, \
385  epiworld::Model<tseq> * m) -> epiworld_double
386 
391 #define EPI_PARAMS(i) m->operator()(i)
392 
397 #define EPI_NEW_MUTFUN(funname,tseq) inline bool \
398  (funname)(\
399  epiworld::Agent<tseq> * p, \
400  epiworld::Virus<tseq> & v, \
401  epiworld::Model<tseq> * m )
402 
403 #define EPI_NEW_MUTFUN_LAMBDA(funname,tseq) \
404  epiworld::MutFun<tseq> funname = \
405  [](epiworld::Agent<tseq> * p, \
406  epiworld::Virus<tseq> & v, \
407  epiworld::Model<tseq> * m) -> void
408 
409 #define EPI_NEW_POSTRECOVERYFUN(funname,tseq) inline void \
410  (funname)( \
411  epiworld::Agent<tseq> * p, \
412  epiworld::Virus<tseq> & v, \
413  epiworld::Model<tseq> * m\
414  )
415 
416 #define EPI_NEW_POSTRECOVERYFUN_LAMBDA(funname,tseq) \
417  epiworld::PostRecoveryFun<tseq> funname = \
418  [](epiworld::Agent<tseq> * p, \
419  epiworld::Virus<tseq> & v , \
420  epiworld::Model<tseq> * m) -> void
421 
422 #define EPI_NEW_VIRUSFUN(funname,tseq) inline epiworld_double \
423  (funname)( \
424  epiworld::Agent<tseq> * p, \
425  epiworld::Virus<tseq> & v, \
426  epiworld::Model<tseq> * m\
427  )
428 
429 #define EPI_NEW_VIRUSFUN_LAMBDA(funname,TSeq) \
430  epiworld::VirusFun<TSeq> funname = \
431  [](epiworld::Agent<TSeq> * p, \
432  epiworld::Virus<TSeq> & v, \
433  epiworld::Model<TSeq> * m) -> epiworld_double
434 
435 #define EPI_RUNIF() m->runif()
436 
437 #define EPIWORLD_RUN(a) \
438  if (a.get_verbose()) \
439  { \
440  printf_epiworld("Running the model...\n");\
441  } \
442  for (epiworld_fast_uint niter = 0; niter < a.get_ndays(); ++niter)
443 
444 #define EPI_TOKENPASTE(a,b) a ## b
445 #define MPAR(num) *(m->EPI_TOKENPASTE(p,num))
446 
447 #define EPI_NEW_UPDATEFUN(funname,tseq) inline void \
448  (funname)(epiworld::Agent<tseq> * p, epiworld::Model<tseq> * m)
449 
450 #define EPI_NEW_UPDATEFUN_LAMBDA(funname,tseq) \
451  epiworld::UpdateFun<tseq> funname = \
452  [](epiworld::Agent<tseq> * p, epiworld::Model<tseq> * m) -> void
453 
454 #define EPI_NEW_GLOBALFUN(funname,tseq) inline void \
455  (funname)(epiworld::Model<tseq>* m)
456 
457 #define EPI_NEW_GLOBALFUN_LAMBDA(funname,tseq) \
458  epiworld::GlobalFun<tseq> funname = \
459  [](epiworld::Model<tseq>* m) -> void
460 
461 
462 #define EPI_NEW_ENTITYTOAGENTFUN(funname,tseq) inline void \
463  (funname)(epiworld::Entity<tseq> & e, epiworld::Model<tseq> * m)
464 
465 #define EPI_NEW_ENTITYTOAGENTFUN_LAMBDA(funname,tseq) \
466  epiworld::EntityToAgentFun<tseq> funname = \
467  [](epiworld::Entity<tseq> & e, epiworld::Model<tseq> * m) -> void
468 
469 // Use this to make it more efficient for storage if the type is small
470 // and the pointer is not needed
471 #define EPI_TYPENAME_TRAITS(tseq, bound) typename std::conditional< \
472  sizeof( tseq ) <= sizeof( bound ), \
473  tseq, \
474  std::shared_ptr< tseq > \
475  >::type
476 
477 #define EPI_IF_TSEQ_LESS_EQ_INT(tseq) \
478  if constexpr (sizeof( tseq ) <= sizeof( int ))
479 
480 #define EPI_CHECK_COALESCE(proposed_, virus_tool_, alt_) \
481  if (static_cast<int>(proposed_) == -99) {\
482  if (static_cast<int>(virus_tool_) == -99) \
483  (proposed_) = (alt_);\
484  else (proposed_) = (virus_tool_);}
485 
486 #endif
487 /*//////////////////////////////////////////////////////////////////////////////
489 
490  End of -include/epiworld/epiworld-macros.hpp-
491 
494 
495 
496 
497 /*//////////////////////////////////////////////////////////////////////////////
499 
500  Start of -include/epiworld/misc.hpp-
501 
504 
505 
506 #ifndef EPIWORLD_MISC_HPP
507 #define EPIWORLD_MISC_HPP
508 
509 template<typename TSeq>
510 class Model;
511 
512 template<typename TSeq>
513 class Agent;
514 
515 // Relevant for anything using vecHasher function ------------------------------
520 template <typename T>
521 struct vecHasher {
522  std::size_t operator()(std::vector< T > const& dat) const noexcept {
523 
524  std::hash< T > hasher;
525  std::size_t hash = hasher(dat[0u]);
526 
527  // ^ makes bitwise XOR
528  // 0x9e3779b9 is a 32 bit constant (comes from the golden ratio)
529  // << is a shift operator, something like lhs * 2^(rhs)
530  if (dat.size() > 1u)
531  for (epiworld_fast_uint i = 1u; i < dat.size(); ++i)
532  hash ^= hasher(dat[i]) + 0x9e3779b9 + (hash<<6) + (hash>>2);
533 
534  return hash;
535 
536  }
537 };
538 
539 template<typename Ta = epiworld_double, typename Tb = epiworld_fast_uint>
540 using MapVec_type = std::unordered_map< std::vector< Ta >, Tb, vecHasher<Ta>>;
541 
554 template<typename TSeq = EPI_DEFAULT_TSEQ>
555 inline TSeq default_sequence(int seq_count);
556 
557 // Making it 'static' so that we don't have problems when including the
558 // header. This is important during the linkage, e.g., in R.
559 // See https://en.cppreference.com/w/cpp/language/storage_duration#Linkage
560 // static int _n_sequences_created = 0;
561 
562 template<>
563 inline bool default_sequence(int seq_count) {
564 
565  if (seq_count == 2)
566  throw std::logic_error("Maximum number of sequence created.");
567 
568  return seq_count++ ? false : true;
569 }
570 
571 template<>
572 inline int default_sequence(int seq_count) {
573  return seq_count++;
574 }
575 
576 template<>
577 inline epiworld_double default_sequence(int seq_count) {
578  return static_cast<epiworld_double>(seq_count++);
579 }
580 
581 template<>
582 inline std::vector<bool> default_sequence(int seq_count) {
583 
584  if (seq_count == 2)
585  throw std::logic_error("Maximum number of sequence created.");
586 
587  return {seq_count++ ? false : true};
588 }
589 
590 template<>
591 inline std::vector<int> default_sequence(int seq_count) {
592  return {seq_count++};
593 }
594 
595 template<>
596 inline std::vector<epiworld_double> default_sequence(int seq_count) {
597  return {static_cast<epiworld_double>(seq_count++)};
598 }
600 
609 template<typename Ta>
610 inline bool IN(const Ta & a, const std::vector< Ta > & b) noexcept
611 {
612  for (const auto & i : b)
613  if (a == i)
614  return true;
615 
616  return false;
617 }
618 
632 template<typename TSeq = EPI_DEFAULT_TSEQ, typename TDbl = epiworld_double >
633 inline int roulette(
634  const std::vector< TDbl > & probs,
635  Model<TSeq> * m
636  )
637 {
638 
639  // Step 1: Computing the prob on none
640  TDbl p_none = 1.0;
641  std::vector< int > certain_infection;
642  certain_infection.reserve(probs.size());
643 
644  for (epiworld_fast_uint p = 0u; p < probs.size(); ++p)
645  {
646  p_none *= (1.0 - probs[p]);
647 
648  if (probs[p] > (1 - 1e-100))
649  certain_infection.push_back(p);
650 
651  }
652 
653  TDbl r = static_cast<TDbl>(m->runif());
654  // If there are one or more probs that go close to 1, sample
655  // uniformly
656  if (certain_infection.size() > 0)
657  return certain_infection[std::floor(r * certain_infection.size())];
658 
659  // Step 2: Calculating the prob of none or single
660  std::vector< TDbl > probs_only_p(probs.size());
661  TDbl p_none_or_single = p_none;
662  for (epiworld_fast_uint p = 0u; p < probs.size(); ++p)
663  {
664  probs_only_p[p] = probs[p] * (p_none / (1.0 - probs[p]));
665  p_none_or_single += probs_only_p[p];
666  }
667 
668  // Step 3: Roulette
669  TDbl cumsum = p_none/p_none_or_single;
670  if (r < cumsum)
671  {
672  return -1;
673  }
674 
675  for (epiworld_fast_uint p = 0u; p < probs.size(); ++p)
676  {
677  // If it yield here, then bingo, the individual will acquire the disease
678  cumsum += probs_only_p[p]/(p_none_or_single);
679  if (r < cumsum)
680  return static_cast<int>(p);
681 
682  }
683 
684 
685  #ifdef EPI_DEBUG
686  printf_epiworld("[epi-debug] roulette::cumsum = %.4f\n", cumsum);
687  #endif
688 
689  return static_cast<int>(probs.size() - 1u);
690 
691 }
692 
693 template<typename TSeq>
694 inline int roulette(std::vector< double > & probs, Model<TSeq> * m)
695 {
696  return roulette<TSeq, double>(probs, m);
697 }
698 
699 template<typename TSeq>
700 inline int roulette(std::vector< float > & probs, Model<TSeq> * m)
701 {
702  return roulette<TSeq, float>(probs, m);
703 }
704 
705 
706 template<typename TSeq>
707 inline int roulette(
708  epiworld_fast_uint nelements,
709  Model<TSeq> * m
710  )
711 {
712 
713  if ((nelements * 2) > m->array_double_tmp.size())
714  {
715  throw std::logic_error(
716  "Trying to sample from more data than there is in roulette!" +
717  std::to_string(nelements) + " vs " +
718  std::to_string(m->array_double_tmp.size())
719  );
720  }
721 
722  // Step 1: Computing the prob on none
723  epiworld_double p_none = 1.0;
724  epiworld_fast_uint ncertain = 0u;
725  // std::vector< int > certain_infection;
726  for (epiworld_fast_uint p = 0u; p < nelements; ++p)
727  {
728  p_none *= (1.0 - m->array_double_tmp[p]);
729 
730  if (m->array_double_tmp[p] > (1 - 1e-100))
731  m->array_double_tmp[nelements + ncertain++] = p;
732  // certain_infection.push_back(p);
733 
734  }
735 
736  epiworld_double r = m->runif();
737  // If there are one or more probs that go close to 1, sample
738  // uniformly
739  if (ncertain > 0u)
740  return m->array_double_tmp[nelements + std::floor(ncertain * r)]; // certain_infection[std::floor(r * certain_infection.size())];
741 
742  // Step 2: Calculating the prob of none or single
743  // std::vector< epiworld_double > probs_only_p;
744  epiworld_double p_none_or_single = p_none;
745  for (epiworld_fast_uint p = 0u; p < nelements; ++p)
746  {
747  m->array_double_tmp[nelements + p] =
748  m->array_double_tmp[p] * (p_none / (1.0 - m->array_double_tmp[p]));
749  p_none_or_single += m->array_double_tmp[nelements + p];
750  }
751 
752  // Step 3: Roulette
753  epiworld_double cumsum = p_none/p_none_or_single;
754  if (r < cumsum)
755  return -1;
756 
757  for (epiworld_fast_uint p = 0u; p < nelements; ++p)
758  {
759  // If it yield here, then bingo, the individual will acquire the disease
760  cumsum += m->array_double_tmp[nelements + p]/(p_none_or_single);
761  if (r < cumsum)
762  return static_cast<int>(p);
763 
764  }
765 
766  return static_cast<int>(nelements - 1u);
767 
768 }
769 
786 template <typename T>
787 inline std::map< std::string, T > read_yaml(std::string fn)
788 {
789 
790  std::ifstream paramsfile(fn);
791 
792  if (!paramsfile)
793  throw std::logic_error("The file " + fn + " was not found.");
794 
795  std::regex pattern("^([^:]+)\\s*[:]\\s*([-]?[0-9]+|[-]?[0-9]*\\.[0-9]+)?\\s*$");
796 
797  std::string line;
798  std::smatch match;
799  auto empty = std::sregex_iterator();
800 
801  // Making room
802  std::map<std::string, T> parameters;
803 
804  while (std::getline(paramsfile, line))
805  {
806 
807  // Is it a comment or an empty line?
808  if (std::regex_match(line, std::regex("^([*].+|//.+|#.+|\\s*)$")))
809  continue;
810 
811  // Finding the pattern, if it doesn't match, then error
812  std::regex_match(line, match, pattern);
813 
814  if (match.empty())
815  throw std::logic_error("Line has invalid format:\n" + line);
816 
817  // Capturing the number
818  std::string anumber = match[2u].str() + match[3u].str();
819  T tmp_num = static_cast<T>(
820  std::strtod(anumber.c_str(), nullptr)
821  );
822 
823  std::string pname = std::regex_replace(
824  match[1u].str(),
825  std::regex("^\\s+|\\s+$"),
826  "");
827 
828  // Adding the parameter to the map
829  parameters[pname] = tmp_num;
830 
831  }
832 
833  return parameters;
834 
835 }
836 
837 #endif
838 /*//////////////////////////////////////////////////////////////////////////////
840 
841  End of -include/epiworld/misc.hpp-
842 
845 
846 
847 /*//////////////////////////////////////////////////////////////////////////////
849 
850  Start of -include/epiworld/progress.hpp-
851 
854 
855 
856 #ifndef EPIWORLD_PROGRESS_HPP
857 #define EPIWORLD_PROGRESS_HPP
858 
859 #ifndef EPIWORLD_PROGRESS_BAR_WIDTH
860 #define EPIWORLD_PROGRESS_BAR_WIDTH 80
861 #endif
862 
866 class Progress {
867 private:
868  int width; ///< Total width size (number of bars)
869  int n; ///< Total number of iterations
870  epiworld_double step_size; ///< Size of the step
871  int last_loc; ///< Last location of the bar
872  int cur_loc; ///< Last location of the bar
873  int i; ///< Current iteration step
874 
875 public:
876  Progress() {};
877  Progress(int n_, int width_);
878  ~Progress() {};
879 
880  void start();
881  void next();
882 
883 
884 };
885 
886 inline Progress::Progress(int n_, int width_) {
887 
888 
889  if (n_ < 0)
890  throw std::invalid_argument("n must be greater or equal than 0.");
891 
892  if (width_ <= 0)
893  throw std::invalid_argument("width must be greater than 0");
894 
895  width = std::max(7, width_ - 7);
896  n = n_;
897  step_size = n == 0? width : static_cast<epiworld_double>(width)/
898  static_cast<epiworld_double>(n);
899  last_loc = 0;
900  i = 0;
901 
902 }
903 
904 inline void Progress::start()
905 {
906 
907  #ifndef EPI_DEBUG
908  for (int j = 0; j < (width); ++j)
909  {
910  printf_epiworld("_");
911  }
912  printf_epiworld("\n");
913  #endif
914 }
915 
916 inline void Progress::next() {
917 
918  if (i == 0)
919  start();
920 
921  cur_loc = std::floor((++i) * step_size);
922 
923  #ifndef EPI_DEBUG
924  for (int j = 0; j < (cur_loc - last_loc); ++j)
925  {
926  printf_epiworld("|");
927  }
928 
929  if (i == n)
930  {
931  printf_epiworld(" done.\n");
932  }
933  #endif
934 
935  last_loc = cur_loc;
936 
937 }
938 
939 #endif
940 /*//////////////////////////////////////////////////////////////////////////////
942 
943  End of -include/epiworld/progress.hpp-
944 
947 
948 
949 
950 /*//////////////////////////////////////////////////////////////////////////////
952 
953  Start of -include/epiworld/modeldiagram-bones.hpp-
954 
957 
958 
959 #ifndef EPIWORLD_MODELDIAGRAM_HPP
960 #define EPIWORLD_MODELDIAGRAM_HPP
961 
962 enum class DiagramType {
963  Mermaid, DOT
964 };
965 
966 class ModelDiagram {
967 private:
968 
969  std::map< std::pair< std::string, std::string >, int > data;
970  std::vector< std::string > states;
971  std::vector< epiworld_double > tprob;
972 
973  void draw_mermaid(std::string fn_output, bool self);
974  void draw_dot(std::string fn_output, bool self);
975 
976  void draw(
977  DiagramType diagram_type,
978  std::string fn_output = "",
979  bool self = false
980  );
981 
982 
983  int n_runs = 0; ///< The number of runs included in the diagram.
984 
1004  void read_transitions(
1005  const std::string & fn_transition
1006  );
1007 
1015  void read_transitions(
1016  const std::vector< std::string > & fns_transition
1017  );
1018 
1025  void transition_probability(bool normalize = true);
1026 
1027  void clear();
1028 
1029 public:
1030 
1031  ModelDiagram() {};
1032 
1033  void draw_from_data(
1034  DiagramType diagram_type,
1035  const std::vector< std::string > & states,
1036  const std::vector< epiworld_double > & tprob,
1037  const std::string & fn_output = "",
1038  bool self = false
1039  );
1040 
1041  void draw_from_file(
1042  DiagramType diagram_type,
1043  const std::string & fn_transition,
1044  const std::string & fn_output = "",
1045  bool self = false
1046  );
1047 
1048  void draw_from_files(
1049  DiagramType diagram_type,
1050  const std::vector< std::string > & fns_transition,
1051  const std::string & fn_output = "",
1052  bool self = false
1053  );
1054 
1055 };
1056 
1057 #endif
1058 /*//////////////////////////////////////////////////////////////////////////////
1060 
1061  End of -include/epiworld/modeldiagram-bones.hpp-
1062 
1065 
1066 
1067 /*//////////////////////////////////////////////////////////////////////////////
1069 
1070  Start of -include/epiworld/modeldiagram-meat.hpp-
1071 
1074 
1075 
1076 #ifndef EPIWORLD_MODELDIAGRAM_MEAT_HPP
1077 #define EPIWORLD_MODELDIAGRAM_MEAT_HPP
1078 
1079 inline void ModelDiagram::read_transitions(
1080  const std::string & fn_transition
1081 ) {
1082 
1083  // Checking if the file exists
1084  std::ifstream file(fn_transition);
1085 
1086  if (!file.is_open())
1087  throw std::runtime_error(
1088  "Could not open the file '" +
1089  fn_transition + "' for reading."
1090  );
1091 
1092  // Reading the data
1093  std::string line;
1094  int i = 0;
1095  while (std::getline(file, line))
1096  {
1097 
1098  // Skipping the first line
1099  if (i++ == 0)
1100  continue;
1101 
1102  std::istringstream iss(line);
1103  #ifdef EPI_DEBUG
1104  int t;
1105  iss >> t;
1106  #endif
1107 
1108  int i_;
1109  std::string from_, to_;
1110  int counts_;
1111 
1112  iss >> i_;
1113 
1114  // Read the quoted strings
1115  iss >> std::quoted(from_) >> std::quoted(to_);
1116 
1117  // Read the integer
1118  iss >> counts_;
1119 
1120  if (counts_ > 0)
1121  {
1122  auto idx = std::make_pair(from_, to_);
1123  if (data.find(idx) == data.end())
1124  data[idx] = counts_;
1125  else
1126  data[idx] += counts_;
1127  }
1128 
1129  }
1130 
1131  // Incrementing the number of runs
1132  this->n_runs++;
1133 
1134 }
1135 
1136 inline void ModelDiagram::read_transitions(
1137  const std::vector< std::string > & fns_transition
1138 )
1139 {
1140 
1141  for (const auto & fn: fns_transition)
1142  this->read_transitions(fn);
1143 
1144  return;
1145 
1146 }
1147 
1148 inline void ModelDiagram::transition_probability(
1149  bool normalize
1150 )
1151 {
1152 
1153  // Generating the map of states
1154  std::set< std::string > states_set;
1155 
1156  for (const auto & d: data)
1157  {
1158  states_set.insert(d.first.first);
1159  states_set.insert(d.first.second);
1160  }
1161 
1162  // Generating the transition matrix
1163  states = std::vector< std::string >(states_set.begin(), states_set.end());
1164  size_t n_states = states.size();
1165  tprob.resize(n_states * n_states);
1166  std::fill(tprob.begin(), tprob.end(), 0.0);
1167 
1168  std::vector< epiworld_double > rowsum(n_states, 0.0);
1169  for (size_t i = 0; i < n_states; ++i)
1170  {
1171 
1172  for (size_t j = 0; j < n_states; ++j)
1173  {
1174 
1175  auto key = std::make_pair(states[i], states[j]);
1176  if (data.find(key) != data.end())
1177  tprob[i + j * n_states] = static_cast<epiworld_double>(
1178  data[key]
1179  );
1180 
1181  if (normalize)
1182  rowsum[i] += tprob[i + j * n_states];
1183 
1184  }
1185 
1186  if (normalize)
1187  {
1188  for (size_t j = 0; j < n_states; ++j)
1189  tprob[i + j * n_states] /= rowsum[i];
1190  }
1191 
1192  }
1193 
1194  return;
1195 
1196 
1197 }
1198 
1199 inline void ModelDiagram::clear()
1200 {
1201  data.clear();
1202  states.clear();
1203  tprob.clear();
1204  n_runs = 0;
1205  return;
1206 }
1207 
1208 inline void ModelDiagram::draw_mermaid(
1209  std::string fn_output,
1210  bool self
1211 ) {
1212  // Getting a sorting vector of indices from the states
1213  // string vector
1214  std::vector< size_t > idx(states.size());
1215  std::iota(idx.begin(), idx.end(), 0u);
1216 
1217  std::sort(
1218  idx.begin(),
1219  idx.end(),
1220  [&states = this->states](size_t i, size_t j) {
1221  return states[i] < states[j];
1222  }
1223  );
1224 
1225  std::vector< std::string > states_ids;
1226  for (size_t i = 0u; i < states.size(); ++i)
1227  states_ids.push_back("s" + std::to_string(i));
1228 
1229  std::string graph = "flowchart LR\n";
1230 
1231  // Declaring the states
1232  for (size_t i = 0u; i < states.size(); ++i)
1233  {
1234  graph += "\t" + states_ids[i] + "[" + states[idx[i]] + "]\n";
1235  }
1236 
1237  // Adding the transitions
1238  size_t n_states = states.size();
1239  for (size_t i = 0u; i < states.size(); ++i)
1240  {
1241  for (size_t j = 0u; j < states.size(); ++j)
1242  {
1243  if (!self && i == j)
1244  continue;
1245 
1246  if (tprob[idx[i] + idx[j] * n_states] > 0.0)
1247  {
1248  graph += "\t" + states_ids[i] + " -->|" +
1249  std::to_string(tprob[idx[i] + idx[j] * n_states]) +
1250  "| " + states_ids[j] + "\n";
1251  }
1252  }
1253  }
1254 
1255  if (fn_output != "")
1256  {
1257  std::ofstream file(fn_output);
1258 
1259  if (!file.is_open())
1260  throw std::runtime_error(
1261  "Could not open the file " +
1262  fn_output +
1263  " for writing."
1264  );
1265 
1266  file << graph;
1267  file.close();
1268 
1269  } else {
1270  printf_epiworld("%s\n", graph.c_str());
1271  }
1272 
1273  return;
1274 }
1275 
1276 inline void ModelDiagram::draw_dot(std::string fn_output, bool self) {
1277  std::vector<size_t> idx(states.size());
1278  std::iota(idx.begin(), idx.end(), 0u);
1279 
1280  std::sort(
1281  idx.begin(),
1282  idx.end(),
1283  [&states = this->states](size_t i, size_t j) {
1284  return states[i] < states[j];
1285  }
1286  );
1287 
1288  std::vector<std::string> states_ids;
1289  for (size_t i = 0u; i < states.size(); ++i)
1290  states_ids.push_back("s" + std::to_string(i));
1291 
1292  std::string graph = "digraph G {\n\trankdir=LR;\n";
1293 
1294  // Declaring the states
1295  for (size_t i = 0u; i < states.size(); ++i)
1296  {
1297  graph += "\t" + states_ids[i] + " [label=\"" + states[idx[i]] + "\"];\n";
1298  }
1299 
1300  // Adding the transitions
1301  size_t n_states = states.size();
1302  for (size_t i = 0u; i < states.size(); ++i)
1303  {
1304  for (size_t j = 0u; j < states.size(); ++j)
1305  {
1306  if (!self && i == j)
1307  continue;
1308 
1309  if (tprob[idx[i] + idx[j] * n_states] > 0.0)
1310  {
1311  graph += "\t" + states_ids[i] + " -> " + states_ids[j] +
1312  " [label=\"" +
1313  std::to_string(tprob[idx[i] + idx[j] * n_states]) +
1314  "\"];\n";
1315  }
1316  }
1317  }
1318 
1319  graph += "}\n";
1320 
1321  if (fn_output != "")
1322  {
1323  std::ofstream file(fn_output);
1324 
1325  if (!file.is_open())
1326  throw std::runtime_error(
1327  "Could not open the file " +
1328  fn_output +
1329  " for writing."
1330  );
1331 
1332  file << graph;
1333  file.close();
1334 
1335  } else {
1336  printf_epiworld("%s\n", graph.c_str());
1337  }
1338 
1339  return;
1340 }
1341 
1342 inline void ModelDiagram::draw(
1343  DiagramType diagram_type,
1344  std::string fn_output,
1345  bool self
1346 )
1347 {
1348  switch (diagram_type) {
1349  case DiagramType::Mermaid:
1350  return draw_mermaid(fn_output, self);
1351  case DiagramType::DOT:
1352  return draw_dot(fn_output, self);
1353  default:
1354  throw std::logic_error("Unknown how to dispatch DiagramType.");
1355  }
1356 }
1357 
1358 inline void ModelDiagram::draw_from_file(
1359  DiagramType diagram_type,
1360  const std::string & fn_transition,
1361  const std::string & fn_output,
1362  bool self
1363 ) {
1364 
1365  this->clear();
1366 
1367  // Loading the transition file
1368  this->read_transitions(fn_transition);
1369 
1370  // Computing the transition probability
1371  this->transition_probability();
1372 
1373  // Actually drawing the diagram
1374  this->draw(diagram_type, fn_output, self);
1375 
1376  return;
1377 
1378 }
1379 
1380 inline void ModelDiagram::draw_from_files(
1381  DiagramType diagram_type,
1382  const std::vector< std::string > & fns_transition,
1383  const std::string & fn_output,
1384  bool self
1385 ) {
1386 
1387  this->clear();
1388 
1389  // Loading the transition files
1390  this->read_transitions(fns_transition);
1391 
1392  // Computing the transition probability
1393  this->transition_probability();
1394 
1395  // Actually drawing the diagram
1396  this->draw(diagram_type, fn_output, self);
1397 
1398  return;
1399 }
1400 
1401 inline void ModelDiagram::draw_from_data(
1402  DiagramType diagram_type,
1403  const std::vector< std::string > & states,
1404  const std::vector< epiworld_double > & tprob,
1405  const std::string & fn_output,
1406  bool self
1407 ) {
1408 
1409  this->clear();
1410 
1411  this->states = states;
1412  this->tprob = tprob;
1413 
1414  this->draw(diagram_type, fn_output, self);
1415 
1416  return;
1417 
1418 }
1419 
1420 #endif
1421 /*//////////////////////////////////////////////////////////////////////////////
1423 
1424  End of -include/epiworld/modeldiagram-meat.hpp-
1425 
1428 
1429 
1430 
1431 /*//////////////////////////////////////////////////////////////////////////////
1433 
1434  Start of -include/epiworld/math/distributions.hpp-
1435 
1438 
1439 
1440 #ifndef EPIWORLD_MATH_DISTRIBUTIONS_HPP
1441 #define EPIWORLD_MATH_DISTRIBUTIONS_HPP
1442 
1443 // Implementing the factorial function
1451 inline double log_factorial(int n)
1452 {
1453  if (n == 0)
1454  return 0.0;
1455  return std::log(static_cast<double>(n)) + log_factorial(n-1);
1456 }
1457 
1468 inline double dpois(
1469  int k,
1470  double lambda,
1471  int max_n = 100,
1472  bool as_log = false
1473  )
1474 {
1475 
1476  if (max_n < k)
1477  throw std::runtime_error("max_n must be greater than k");
1478 
1479  double res = k * std::log(lambda) - lambda - log_factorial(
1480  std::min(k, max_n)
1481  );
1482 
1483  return as_log ? res : std::exp(res);
1484 }
1485 
1506 inline double dgenint(
1507  int g,
1508  double S,
1509  double p_c,
1510  double p_i,
1511  double p_r,
1512  double & p_0_approx,
1513  double & normalizing,
1514  int max_contacts = 200,
1515  int max_days = 200
1516  ) {
1517 
1518  if ((g < 1) || (g > max_days))
1519  return 0.0;
1520 
1521  if (p_0_approx < 0.0)
1522  {
1523 
1524  p_0_approx = 0.0;
1525  for (int i = 0; i < max_contacts; ++i)
1526  {
1527 
1528  p_0_approx += std::exp(
1529  dpois(i, S * p_c, max_contacts, true) +
1530  std::log(1.0 - p_i) * static_cast<double>(i)
1531  );
1532 
1533  }
1534  }
1535 
1536  double g_dbl = static_cast<double>(g);
1537 
1538  if (normalizing < 0.0)
1539  {
1540 
1541  normalizing = 1.0;
1542  double log1_p_r = std::log(1.0 - p_r);
1543  double log_p_r = std::log(p_r);
1544  double log_p_0_approx = std::log(p_0_approx);
1545  for (int i = 1; i <= max_days; ++i)
1546  {
1547 
1548  double i_dbl = static_cast<double>(i);
1549 
1550  normalizing -= std::exp(
1551  log1_p_r * (i_dbl - 1.0) +
1552  log_p_r +
1553  log_p_0_approx * (i_dbl - 1.0)
1554  );
1555  }
1556 
1557  }
1558 
1559 
1560  return std::exp(
1561  std::log(1 - p_r) * (g_dbl)+
1562  std::log(p_0_approx) * (g_dbl - 1.0) +
1563  std::log(1.0 - p_0_approx) -
1564  std::log(normalizing)
1565  );
1566 
1567 }
1568 
1569 // Mean of the generation interval
1581 inline double gen_int_mean(
1582  double S,
1583  double p_c,
1584  double p_i,
1585  double p_r,
1586  int max_days = 200,
1587  int max_n = 200
1588  ) {
1589 
1590  double mean = 0.0;
1591  double p_0_approx = -1.0;
1592  double normalizing = -1.0;
1593  for (int i = 1; i < max_days; ++i)
1594  {
1595  mean +=
1596  static_cast<double>(i) *
1597  dgenint(
1598  i, S, p_c, p_i, p_r, p_0_approx, normalizing, max_n, max_days
1599  );
1600 
1601  }
1602 
1603  return mean;
1604 
1605 }
1606 
1607 #endif
1608 /*//////////////////////////////////////////////////////////////////////////////
1610 
1611  End of -include/epiworld/math/distributions.hpp-
1612 
1615 
1616 
1617 
1618 /*//////////////////////////////////////////////////////////////////////////////
1620 
1621  Start of -include/epiworld/math/lfmcmc.hpp-
1622 
1625 
1626 
1627 #ifndef EPIWORLD_LFMCMC_HPP
1628 #define EPIWORLD_LFMCMC_HPP
1629 
1630 /*//////////////////////////////////////////////////////////////////////////////
1632 
1633  Start of -include/epiworld/math/lfmcmc/lfmcmc-bones.hpp-
1634 
1637 
1638 
1639 #ifndef EPIWORLD_LFMCMC_BONES_HPP
1640 #define EPIWORLD_LFMCMC_BONES_HPP
1641 
1642 #ifndef epiworld_double
1643  #define epiworld_double float
1644 #endif
1645 
1646 
1647 template<typename TData>
1648 class LFMCMC;
1649 
1650 template<typename TData>
1651 using LFMCMCSimFun = std::function<TData(const std::vector< epiworld_double >&,LFMCMC<TData>*)>;
1652 
1653 template<typename TData>
1654 using LFMCMCSummaryFun = std::function<void(std::vector< epiworld_double >&,const TData&,LFMCMC<TData>*)>;
1655 
1656 template<typename TData>
1657 using LFMCMCProposalFun = std::function<void(std::vector< epiworld_double >&,const std::vector< epiworld_double >&,LFMCMC<TData>*)>;
1658 
1659 template<typename TData>
1660 using LFMCMCKernelFun = std::function<epiworld_double(const std::vector< epiworld_double >&,const std::vector< epiworld_double >&,epiworld_double,LFMCMC<TData>*)>;
1661 
1669 template<typename TData>
1670 inline void proposal_fun_normal(
1671  std::vector< epiworld_double >& new_params,
1672  const std::vector< epiworld_double >& old_params,
1673  LFMCMC<TData>* m
1674 );
1675 
1688 template<typename TData>
1689 inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
1690  epiworld_double scale,
1691  epiworld_double lb = std::numeric_limits<epiworld_double>::min(),
1692  epiworld_double ub = std::numeric_limits<epiworld_double>::max()
1693 );
1694 
1706 template<typename TData>
1707 inline void proposal_fun_unif(
1708  std::vector< epiworld_double >& new_params,
1709  const std::vector< epiworld_double >& old_params,
1710  LFMCMC<TData>* m
1711 );
1712 
1723 template<typename TData>
1724 inline epiworld_double kernel_fun_uniform(
1725  const std::vector< epiworld_double >& simulated_stats,
1726  const std::vector< epiworld_double >& observed_stats,
1727  epiworld_double epsilon,
1728  LFMCMC<TData>* m
1729 );
1730 
1742 template<typename TData>
1743 inline epiworld_double kernel_fun_gaussian(
1744  const std::vector< epiworld_double >& simulated_stats,
1745  const std::vector< epiworld_double >& observed_stats,
1746  epiworld_double epsilon,
1747  LFMCMC<TData>* m
1748 );
1749 
1755 template<typename TData>
1756 class LFMCMC {
1757 private:
1758 
1759  // Random number sampling
1760  std::shared_ptr< std::mt19937 > m_engine = nullptr;
1761 
1762  std::shared_ptr< std::uniform_real_distribution<> > runifd =
1763  std::make_shared< std::uniform_real_distribution<> >(0.0, 1.0);
1764 
1765  std::shared_ptr< std::normal_distribution<> > rnormd =
1766  std::make_shared< std::normal_distribution<> >(0.0);
1767 
1768  std::shared_ptr< std::gamma_distribution<> > rgammad =
1769  std::make_shared< std::gamma_distribution<> >();
1770 
1771  // Process data
1772  TData m_observed_data;
1773  std::vector< TData > * m_simulated_data = nullptr;
1774 
1775  // Information about the size of the process
1776  size_t m_n_samples;
1777  size_t m_n_stats;
1778  size_t m_n_params;
1779 
1780  epiworld_double m_epsilon;
1781 
1782  std::vector< epiworld_double > m_initial_params; ///< Initial parameters
1783  std::vector< epiworld_double > m_current_proposed_params; ///< Proposed parameters for the next sample
1784  std::vector< epiworld_double > m_current_accepted_params; ///< Most recently accepted parameters (current state of MCMC)
1785  std::vector< epiworld_double > m_current_proposed_stats; ///< Statistics from simulation run with proposed parameters
1786  std::vector< epiworld_double > m_current_accepted_stats; ///< Statistics from simulation run with most recently accepted params
1787 
1788  std::vector< epiworld_double > m_observed_stats; ///< Observed statistics
1789 
1790  std::vector< epiworld_double > m_all_sample_params; ///< Parameter samples
1791  std::vector< epiworld_double > m_all_sample_stats; ///< Statistic samples
1792  std::vector< bool > m_all_sample_acceptance; ///< Indicator if sample was accepted
1793  std::vector< epiworld_double > m_all_sample_drawn_prob; ///< Drawn probabilities (runif()) for each sample
1794  std::vector< epiworld_double > m_all_sample_kernel_scores; ///< Kernel scores for each sample
1795 
1796  std::vector< epiworld_double > m_all_accepted_params; ///< Posterior distribution of parameters from accepted samples
1797  std::vector< epiworld_double > m_all_accepted_stats; ///< Posterior distribution of statistics from accepted samples
1798  std::vector< epiworld_double > m_all_accepted_kernel_scores; ///< Kernel scores for each accepted sample
1799 
1800  // Functions
1801  LFMCMCSimFun<TData> m_simulation_fun;
1802  LFMCMCSummaryFun<TData> m_summary_fun;
1803  LFMCMCProposalFun<TData> m_proposal_fun = proposal_fun_normal<TData>;
1804  LFMCMCKernelFun<TData> m_kernel_fun = kernel_fun_uniform<TData>;
1805 
1806  // Misc
1807  std::vector< std::string > m_param_names;
1808  std::vector< std::string > m_stat_names;
1809 
1810  std::chrono::time_point<std::chrono::steady_clock> m_start_time;
1811  std::chrono::time_point<std::chrono::steady_clock> m_end_time;
1812 
1813  // Timing
1814  // std::chrono::milliseconds
1815  std::chrono::duration<epiworld_double,std::micro> m_elapsed_time =
1816  std::chrono::duration<epiworld_double,std::micro>::zero();
1817 
1818  inline void get_elapsed_time(
1819  std::string unit,
1820  epiworld_double * last_elapsed,
1821  std::string * unit_abbr,
1822  bool print
1823  ) const;
1824 
1825  void chrono_start();
1826  void chrono_end();
1827 
1828  // Progress
1829  bool verbose = true;
1830  Progress progress_bar;
1831 
1832 public:
1833 
1834  void run(
1835  std::vector< epiworld_double > params_init_,
1836  size_t n_samples_,
1837  epiworld_double epsilon_,
1838  int seed = -1
1839  );
1840 
1841  LFMCMC() {};
1842  LFMCMC(const TData & observed_data_) : m_observed_data(observed_data_) {};
1843  ~LFMCMC() {};
1844 
1845  // Setting LFMCMC variables
1846  void set_observed_data(const TData & observed_data_) {m_observed_data = observed_data_;};
1847 
1848  void set_proposal_fun(LFMCMCProposalFun<TData> fun);
1849  void set_simulation_fun(LFMCMCSimFun<TData> fun);
1850  void set_summary_fun(LFMCMCSummaryFun<TData> fun);
1851  void set_kernel_fun(LFMCMCKernelFun<TData> fun);
1852 
1853  void set_params_names(std::vector< std::string > names);
1854  void set_stats_names(std::vector< std::string > names);
1855 
1862  void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
1863  std::shared_ptr< std::mt19937 > & get_rand_endgine();
1864  void seed(epiworld_fast_uint s);
1865  void set_rand_gamma(epiworld_double alpha, epiworld_double beta);
1866  epiworld_double runif();
1867  epiworld_double rnorm();
1868  epiworld_double rgamma();
1869  epiworld_double runif(epiworld_double lb, epiworld_double ub);
1870  epiworld_double rnorm(epiworld_double mean, epiworld_double sd);
1871  epiworld_double rgamma(epiworld_double alpha, epiworld_double beta);
1873 
1874  // Accessing parameters of the function
1875  size_t get_n_samples() const {return m_n_samples;};
1876  size_t get_n_stats() const {return m_n_stats;};
1877  size_t get_n_params() const {return m_n_params;};
1878  epiworld_double get_epsilon() const {return m_epsilon;};
1879 
1880  const std::vector< epiworld_double > & get_initial_params() const {return m_initial_params;};
1881  const std::vector< epiworld_double > & get_current_proposed_params() const {return m_current_proposed_params;};
1882  const std::vector< epiworld_double > & get_current_accepted_params() const {return m_current_accepted_params;};
1883  const std::vector< epiworld_double > & get_current_proposed_stats() const {return m_current_proposed_stats;};
1884  const std::vector< epiworld_double > & get_current_accepted_stats() const {return m_current_accepted_stats;};
1885 
1886  const std::vector< epiworld_double > & get_observed_stats() const {return m_observed_stats;};
1887 
1888  const std::vector< epiworld_double > & get_all_sample_params() const {return m_all_sample_params;};
1889  const std::vector< epiworld_double > & get_all_sample_stats() const {return m_all_sample_stats;};
1890  const std::vector< bool > & get_all_sample_acceptance() const {return m_all_sample_acceptance;};
1891  const std::vector< epiworld_double > & get_all_sample_drawn_prob() const {return m_all_sample_drawn_prob;};
1892  const std::vector< epiworld_double > & get_all_sample_kernel_scores() const {return m_all_sample_kernel_scores;};
1893 
1894  const std::vector< epiworld_double > & get_all_accepted_params() const {return m_all_accepted_params;};
1895  const std::vector< epiworld_double > & get_all_accepted_stats() const {return m_all_accepted_stats;};
1896  const std::vector< epiworld_double > & get_all_accepted_kernel_scores() const {return m_all_accepted_kernel_scores;};
1897 
1898  std::vector< TData > * get_simulated_data() const {return m_simulated_data;};
1899 
1900  std::vector< epiworld_double > get_mean_params();
1901  std::vector< epiworld_double > get_mean_stats();
1902 
1903  // Printing
1904  LFMCMC<TData> & verbose_off();
1905  LFMCMC<TData> & verbose_on();
1906  void print(size_t burnin = 0u) const;
1907 
1908 };
1909 
1910 #endif
1911 /*//////////////////////////////////////////////////////////////////////////////
1913 
1914  End of -include/epiworld/math/lfmcmc/lfmcmc-bones.hpp-
1915 
1918 
1919 
1920 /*//////////////////////////////////////////////////////////////////////////////
1922 
1923  Start of -include/epiworld/math/lfmcmc/lfmcmc-meat.hpp-
1924 
1927 
1928 
1929 #ifndef EPIWORLD_LFMCMC_MEAT_HPP
1930 #define EPIWORLD_LFMCMC_MEAT_HPP
1931 
1932 /*//////////////////////////////////////////////////////////////////////////////
1934 
1935  Start of -include/epiworld/math/lfmcmc/lfmcmc-bones.hpp-
1936 
1939 
1940 
1941 #ifndef EPIWORLD_LFMCMC_BONES_HPP
1942 #define EPIWORLD_LFMCMC_BONES_HPP
1943 
1944 #ifndef epiworld_double
1945  #define epiworld_double float
1946 #endif
1947 
1948 
1949 template<typename TData>
1950 class LFMCMC;
1951 
1952 template<typename TData>
1953 using LFMCMCSimFun = std::function<TData(const std::vector< epiworld_double >&,LFMCMC<TData>*)>;
1954 
1955 template<typename TData>
1956 using LFMCMCSummaryFun = std::function<void(std::vector< epiworld_double >&,const TData&,LFMCMC<TData>*)>;
1957 
1958 template<typename TData>
1959 using LFMCMCProposalFun = std::function<void(std::vector< epiworld_double >&,const std::vector< epiworld_double >&,LFMCMC<TData>*)>;
1960 
1961 template<typename TData>
1962 using LFMCMCKernelFun = std::function<epiworld_double(const std::vector< epiworld_double >&,const std::vector< epiworld_double >&,epiworld_double,LFMCMC<TData>*)>;
1963 
1971 template<typename TData>
1972 inline void proposal_fun_normal(
1973  std::vector< epiworld_double >& new_params,
1974  const std::vector< epiworld_double >& old_params,
1975  LFMCMC<TData>* m
1976 );
1977 
1990 template<typename TData>
1991 inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
1992  epiworld_double scale,
1993  epiworld_double lb = std::numeric_limits<epiworld_double>::min(),
1994  epiworld_double ub = std::numeric_limits<epiworld_double>::max()
1995 );
1996 
2008 template<typename TData>
2009 inline void proposal_fun_unif(
2010  std::vector< epiworld_double >& new_params,
2011  const std::vector< epiworld_double >& old_params,
2012  LFMCMC<TData>* m
2013 );
2014 
2025 template<typename TData>
2026 inline epiworld_double kernel_fun_uniform(
2027  const std::vector< epiworld_double >& simulated_stats,
2028  const std::vector< epiworld_double >& observed_stats,
2029  epiworld_double epsilon,
2030  LFMCMC<TData>* m
2031 );
2032 
2044 template<typename TData>
2045 inline epiworld_double kernel_fun_gaussian(
2046  const std::vector< epiworld_double >& simulated_stats,
2047  const std::vector< epiworld_double >& observed_stats,
2048  epiworld_double epsilon,
2049  LFMCMC<TData>* m
2050 );
2051 
2057 template<typename TData>
2058 class LFMCMC {
2059 private:
2060 
2061  // Random number sampling
2062  std::shared_ptr< std::mt19937 > m_engine = nullptr;
2063 
2064  std::shared_ptr< std::uniform_real_distribution<> > runifd =
2065  std::make_shared< std::uniform_real_distribution<> >(0.0, 1.0);
2066 
2067  std::shared_ptr< std::normal_distribution<> > rnormd =
2068  std::make_shared< std::normal_distribution<> >(0.0);
2069 
2070  std::shared_ptr< std::gamma_distribution<> > rgammad =
2071  std::make_shared< std::gamma_distribution<> >();
2072 
2073  // Process data
2074  TData m_observed_data;
2075  std::vector< TData > * m_simulated_data = nullptr;
2076 
2077  // Information about the size of the process
2078  size_t m_n_samples;
2079  size_t m_n_stats;
2080  size_t m_n_params;
2081 
2082  epiworld_double m_epsilon;
2083 
2084  std::vector< epiworld_double > m_initial_params; ///< Initial parameters
2085  std::vector< epiworld_double > m_current_proposed_params; ///< Proposed parameters for the next sample
2086  std::vector< epiworld_double > m_current_accepted_params; ///< Most recently accepted parameters (current state of MCMC)
2087  std::vector< epiworld_double > m_current_proposed_stats; ///< Statistics from simulation run with proposed parameters
2088  std::vector< epiworld_double > m_current_accepted_stats; ///< Statistics from simulation run with most recently accepted params
2089 
2090  std::vector< epiworld_double > m_observed_stats; ///< Observed statistics
2091 
2092  std::vector< epiworld_double > m_all_sample_params; ///< Parameter samples
2093  std::vector< epiworld_double > m_all_sample_stats; ///< Statistic samples
2094  std::vector< bool > m_all_sample_acceptance; ///< Indicator if sample was accepted
2095  std::vector< epiworld_double > m_all_sample_drawn_prob; ///< Drawn probabilities (runif()) for each sample
2096  std::vector< epiworld_double > m_all_sample_kernel_scores; ///< Kernel scores for each sample
2097 
2098  std::vector< epiworld_double > m_all_accepted_params; ///< Posterior distribution of parameters from accepted samples
2099  std::vector< epiworld_double > m_all_accepted_stats; ///< Posterior distribution of statistics from accepted samples
2100  std::vector< epiworld_double > m_all_accepted_kernel_scores; ///< Kernel scores for each accepted sample
2101 
2102  // Functions
2103  LFMCMCSimFun<TData> m_simulation_fun;
2104  LFMCMCSummaryFun<TData> m_summary_fun;
2105  LFMCMCProposalFun<TData> m_proposal_fun = proposal_fun_normal<TData>;
2106  LFMCMCKernelFun<TData> m_kernel_fun = kernel_fun_uniform<TData>;
2107 
2108  // Misc
2109  std::vector< std::string > m_param_names;
2110  std::vector< std::string > m_stat_names;
2111 
2112  std::chrono::time_point<std::chrono::steady_clock> m_start_time;
2113  std::chrono::time_point<std::chrono::steady_clock> m_end_time;
2114 
2115  // Timing
2116  // std::chrono::milliseconds
2117  std::chrono::duration<epiworld_double,std::micro> m_elapsed_time =
2118  std::chrono::duration<epiworld_double,std::micro>::zero();
2119 
2120  inline void get_elapsed_time(
2121  std::string unit,
2122  epiworld_double * last_elapsed,
2123  std::string * unit_abbr,
2124  bool print
2125  ) const;
2126 
2127  void chrono_start();
2128  void chrono_end();
2129 
2130  // Progress
2131  bool verbose = true;
2132  Progress progress_bar;
2133 
2134 public:
2135 
2136  void run(
2137  std::vector< epiworld_double > params_init_,
2138  size_t n_samples_,
2139  epiworld_double epsilon_,
2140  int seed = -1
2141  );
2142 
2143  LFMCMC() {};
2144  LFMCMC(const TData & observed_data_) : m_observed_data(observed_data_) {};
2145  ~LFMCMC() {};
2146 
2147  // Setting LFMCMC variables
2148  void set_observed_data(const TData & observed_data_) {m_observed_data = observed_data_;};
2149 
2150  void set_proposal_fun(LFMCMCProposalFun<TData> fun);
2151  void set_simulation_fun(LFMCMCSimFun<TData> fun);
2152  void set_summary_fun(LFMCMCSummaryFun<TData> fun);
2153  void set_kernel_fun(LFMCMCKernelFun<TData> fun);
2154 
2155  void set_params_names(std::vector< std::string > names);
2156  void set_stats_names(std::vector< std::string > names);
2157 
2164  void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
2165  std::shared_ptr< std::mt19937 > & get_rand_endgine();
2166  void seed(epiworld_fast_uint s);
2167  void set_rand_gamma(epiworld_double alpha, epiworld_double beta);
2168  epiworld_double runif();
2169  epiworld_double rnorm();
2170  epiworld_double rgamma();
2171  epiworld_double runif(epiworld_double lb, epiworld_double ub);
2172  epiworld_double rnorm(epiworld_double mean, epiworld_double sd);
2173  epiworld_double rgamma(epiworld_double alpha, epiworld_double beta);
2175 
2176  // Accessing parameters of the function
2177  size_t get_n_samples() const {return m_n_samples;};
2178  size_t get_n_stats() const {return m_n_stats;};
2179  size_t get_n_params() const {return m_n_params;};
2180  epiworld_double get_epsilon() const {return m_epsilon;};
2181 
2182  const std::vector< epiworld_double > & get_initial_params() const {return m_initial_params;};
2183  const std::vector< epiworld_double > & get_current_proposed_params() const {return m_current_proposed_params;};
2184  const std::vector< epiworld_double > & get_current_accepted_params() const {return m_current_accepted_params;};
2185  const std::vector< epiworld_double > & get_current_proposed_stats() const {return m_current_proposed_stats;};
2186  const std::vector< epiworld_double > & get_current_accepted_stats() const {return m_current_accepted_stats;};
2187 
2188  const std::vector< epiworld_double > & get_observed_stats() const {return m_observed_stats;};
2189 
2190  const std::vector< epiworld_double > & get_all_sample_params() const {return m_all_sample_params;};
2191  const std::vector< epiworld_double > & get_all_sample_stats() const {return m_all_sample_stats;};
2192  const std::vector< bool > & get_all_sample_acceptance() const {return m_all_sample_acceptance;};
2193  const std::vector< epiworld_double > & get_all_sample_drawn_prob() const {return m_all_sample_drawn_prob;};
2194  const std::vector< epiworld_double > & get_all_sample_kernel_scores() const {return m_all_sample_kernel_scores;};
2195 
2196  const std::vector< epiworld_double > & get_all_accepted_params() const {return m_all_accepted_params;};
2197  const std::vector< epiworld_double > & get_all_accepted_stats() const {return m_all_accepted_stats;};
2198  const std::vector< epiworld_double > & get_all_accepted_kernel_scores() const {return m_all_accepted_kernel_scores;};
2199 
2200  std::vector< TData > * get_simulated_data() const {return m_simulated_data;};
2201 
2202  std::vector< epiworld_double > get_mean_params();
2203  std::vector< epiworld_double > get_mean_stats();
2204 
2205  // Printing
2206  LFMCMC<TData> & verbose_off();
2207  LFMCMC<TData> & verbose_on();
2208  void print(size_t burnin = 0u) const;
2209 
2210 };
2211 
2212 #endif
2213 /*//////////////////////////////////////////////////////////////////////////////
2215 
2216  End of -include/epiworld/math/lfmcmc/lfmcmc-bones.hpp-
2217 
2220 
2221 
2222 
2230 template<typename TData>
2231 inline void proposal_fun_normal(
2232  std::vector< epiworld_double >& new_params,
2233  const std::vector< epiworld_double >& old_params,
2234  LFMCMC<TData>* m
2235 ) {
2236 
2237  for (size_t p = 0u; p < m->get_n_params(); ++p)
2238  new_params[p] = old_params[p] + m->rnorm();
2239 
2240  return;
2241 }
2242 
2255 template<typename TData>
2256 inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
2257  epiworld_double scale,
2258  epiworld_double lb,
2259  epiworld_double ub
2260 ) {
2261 
2262  LFMCMCProposalFun<TData> fun =
2263  [scale,lb,ub](
2264  std::vector< epiworld_double >& new_params,
2265  const std::vector< epiworld_double >& old_params,
2266  LFMCMC<TData>* m
2267  ) {
2268 
2269  // Making the proposal
2270  for (size_t p = 0u; p < m->get_n_params(); ++p)
2271  new_params[p] = old_params[p] + m->rnorm() * scale;
2272 
2273  // Checking boundaries
2274  epiworld_double d = ub - lb;
2275  int odd;
2276  epiworld_double d_above, d_below;
2277  for (auto & p : new_params)
2278  {
2279 
2280  // Correcting if parameter goes above the upper bound
2281  if (p > ub)
2282  {
2283  d_above = p - ub;
2284  odd = static_cast<int>(std::floor(d_above / d)) % 2;
2285  d_above = d_above - std::floor(d_above / d) * d;
2286 
2287  p = (lb + d_above) * odd +
2288  (ub - d_above) * (1 - odd);
2289 
2290  // Correcting if parameter goes below upper bound
2291  } else if (p < lb)
2292  {
2293  d_below = lb - p;
2294  int odd = static_cast<int>(std::floor(d_below / d)) % 2;
2295  d_below = d_below - std::floor(d_below / d) * d;
2296 
2297  p = (ub - d_below) * odd +
2298  (lb + d_below) * (1 - odd);
2299  }
2300 
2301  }
2302 
2303  #ifdef EPI_DEBUG
2304  for (auto & p : new_params)
2305  if (p < lb || p > ub)
2306  throw std::range_error("The parameter is out of bounds.");
2307  #endif
2308 
2309 
2310  return;
2311 
2312  };
2313 
2314  return fun;
2315 }
2316 
2328 template<typename TData>
2329 inline void proposal_fun_unif(
2330  std::vector< epiworld_double >& new_params,
2331  const std::vector< epiworld_double >& old_params,
2332  LFMCMC<TData>* m
2333 ) {
2334 
2335  for (size_t p = 0u; p < m->get_n_params(); ++p)
2336  new_params[p] = (old_params[p] + m->runif(-1.0, 1.0));
2337 
2338  return;
2339 }
2340 
2351 template<typename TData>
2352 inline epiworld_double kernel_fun_uniform(
2353  const std::vector< epiworld_double >& simulated_stats,
2354  const std::vector< epiworld_double >& observed_stats,
2355  epiworld_double epsilon,
2356  LFMCMC<TData>* m
2357 ) {
2358 
2359  epiworld_double ans = 0.0;
2360  for (size_t p = 0u; p < m->get_n_params(); ++p)
2361  ans += std::pow(observed_stats[p] - simulated_stats[p], 2.0);
2362 
2363  return std::sqrt(ans) < epsilon ? 1.0 : 0.0;
2364 
2365 }
2366 
2367 #define sqrt2pi() 2.5066282746310002416
2368 
2380 template<typename TData>
2381 inline epiworld_double kernel_fun_gaussian(
2382  const std::vector< epiworld_double >& simulated_stats,
2383  const std::vector< epiworld_double >& observed_stats,
2384  epiworld_double epsilon,
2385  LFMCMC<TData>* m
2386 ) {
2387 
2388  epiworld_double ans = 0.0;
2389  for (size_t p = 0u; p < m->get_n_params(); ++p)
2390  ans += std::pow(observed_stats[p] - simulated_stats[p], 2.0);
2391 
2392  return std::exp(
2393  -.5 * (ans/std::pow(1 + std::pow(epsilon, 2.0)/3.0, 2.0))
2394  ) / sqrt2pi() ;
2395 
2396 }
2397 
2398 
2399 template<typename TData>
2400 inline void LFMCMC<TData>::set_proposal_fun(LFMCMCProposalFun<TData> fun)
2401 {
2402  m_proposal_fun = fun;
2403 }
2404 
2405 template<typename TData>
2406 inline void LFMCMC<TData>::set_simulation_fun(LFMCMCSimFun<TData> fun)
2407 {
2408  m_simulation_fun = fun;
2409 }
2410 
2411 template<typename TData>
2412 inline void LFMCMC<TData>::set_summary_fun(LFMCMCSummaryFun<TData> fun)
2413 {
2414  m_summary_fun = fun;
2415 }
2416 
2417 template<typename TData>
2418 inline void LFMCMC<TData>::set_kernel_fun(LFMCMCKernelFun<TData> fun)
2419 {
2420  m_kernel_fun = fun;
2421 }
2422 
2423 
2424 template<typename TData>
2425 inline void LFMCMC<TData>::run(
2426  std::vector< epiworld_double > params_init_,
2427  size_t n_samples_,
2428  epiworld_double epsilon_,
2429  int seed
2430  )
2431 {
2432 
2433  // Starting timing
2434  chrono_start();
2435 
2436  // Setting the baseline parameters of the model
2437  m_n_samples = n_samples_;
2438  m_epsilon = epsilon_;
2439  m_initial_params = params_init_;
2440  m_n_params = params_init_.size();
2441 
2442  if (seed >= 0)
2443  this->seed(seed);
2444 
2445  m_current_proposed_params.resize(m_n_params);
2446  m_current_accepted_params.resize(m_n_params);
2447 
2448  if (m_simulated_data != nullptr)
2449  m_simulated_data->resize(m_n_samples);
2450 
2451  m_current_accepted_params = m_initial_params;
2452  m_current_proposed_params = m_initial_params;
2453 
2454  // Computing the baseline sufficient statistics
2455  m_summary_fun(m_observed_stats, m_observed_data, this);
2456  m_n_stats = m_observed_stats.size();
2457 
2458  // Reserving size
2459  m_current_proposed_stats.resize(m_n_stats);
2460  m_current_accepted_stats.resize(m_n_stats);
2461  m_all_sample_drawn_prob.resize(m_n_samples);
2462  m_all_sample_acceptance.resize(m_n_samples, false);
2463  m_all_sample_params.resize(m_n_samples * m_n_params);
2464  m_all_sample_stats.resize(m_n_samples * m_n_stats);
2465  m_all_sample_kernel_scores.resize(m_n_samples);
2466 
2467  m_all_accepted_params.resize(m_n_samples * m_n_params);
2468  m_all_accepted_stats.resize(m_n_samples * m_n_stats);
2469  m_all_accepted_kernel_scores.resize(m_n_samples);
2470 
2471  TData data_i = m_simulation_fun(m_initial_params, this);
2472 
2473  m_summary_fun(m_current_proposed_stats, data_i, this);
2474  m_all_accepted_kernel_scores[0u] = m_kernel_fun(
2475  m_current_proposed_stats, m_observed_stats, m_epsilon, this
2476  );
2477 
2478  // Recording statistics
2479  for (size_t i = 0u; i < m_n_stats; ++i)
2480  m_all_sample_stats[i] = m_current_proposed_stats[i];
2481 
2482  m_current_accepted_stats = m_current_proposed_stats;
2483 
2484  for (size_t k = 0u; k < m_n_params; ++k)
2485  m_all_accepted_params[k] = m_initial_params[k];
2486 
2487  for (size_t k = 0u; k < m_n_params; ++k)
2488  m_all_sample_params[k] = m_initial_params[k];
2489 
2490  // Init progress bar
2491  progress_bar = Progress(m_n_samples, 80);
2492 
2493  // Run LFMCMC
2494  for (size_t i = 1u; i < m_n_samples; ++i)
2495  {
2496  // Step 1: Generate a proposal and store it in m_current_proposed_params
2497  m_proposal_fun(m_current_proposed_params, m_current_accepted_params, this);
2498 
2499  // Step 2: Using m_current_proposed_params, simulate data
2500  TData data_i = m_simulation_fun(m_current_proposed_params, this);
2501 
2502  // Are we storing the data?
2503  if (m_simulated_data != nullptr)
2504  m_simulated_data->operator[](i) = data_i;
2505 
2506  // Step 3: Generate the summary statistics of the data
2507  m_summary_fun(m_current_proposed_stats, data_i, this);
2508 
2509  // Step 4: Compute the hastings ratio using the kernel function
2510  epiworld_double hr = m_kernel_fun(
2511  m_current_proposed_stats, m_observed_stats, m_epsilon, this
2512  );
2513 
2514  m_all_sample_kernel_scores[i] = hr;
2515 
2516  // Storing data
2517  for (size_t k = 0u; k < m_n_params; ++k)
2518  m_all_sample_params[i * m_n_params + k] = m_current_proposed_params[k];
2519 
2520  for (size_t k = 0u; k < m_n_stats; ++k)
2521  m_all_sample_stats[i * m_n_stats + k] = m_current_proposed_stats[k];
2522 
2523  // Running Hastings ratio
2524  epiworld_double r = runif();
2525  m_all_sample_drawn_prob[i] = r;
2526 
2527  // Step 5: Update if likely
2528  if (r < std::min(static_cast<epiworld_double>(1.0), hr / m_all_accepted_kernel_scores[i - 1u]))
2529  {
2530  m_all_accepted_kernel_scores[i] = hr;
2531  m_all_sample_acceptance[i] = true;
2532 
2533  for (size_t k = 0u; k < m_n_stats; ++k)
2534  m_all_accepted_stats[i * m_n_stats + k] =
2535  m_current_proposed_stats[k];
2536 
2537  m_current_accepted_params = m_current_proposed_params;
2538  m_current_accepted_stats = m_current_proposed_stats;
2539  } else
2540  {
2541 
2542  for (size_t k = 0u; k < m_n_stats; ++k)
2543  m_all_accepted_stats[i * m_n_stats + k] =
2544  m_all_accepted_stats[(i - 1) * m_n_stats + k];
2545 
2546  m_all_accepted_kernel_scores[i] = m_all_accepted_kernel_scores[i - 1u];
2547  }
2548 
2549 
2550  for (size_t k = 0u; k < m_n_params; ++k)
2551  m_all_accepted_params[i * m_n_params + k] = m_current_accepted_params[k];
2552 
2553  if (verbose)
2554  progress_bar.next();
2555 
2556  }
2557 
2558  // End timing
2559  chrono_end();
2560 
2561 }
2562 
2563 
2564 template<typename TData>
2565 inline epiworld_double LFMCMC<TData>::runif()
2566 {
2567  return runifd->operator()(*m_engine);
2568 }
2569 
2570 template<typename TData>
2571 inline epiworld_double LFMCMC<TData>::runif(
2572  epiworld_double lb,
2573  epiworld_double ub
2574 )
2575 {
2576  return runifd->operator()(*m_engine) * (ub - lb) + lb;
2577 }
2578 
2579 template<typename TData>
2580 inline epiworld_double LFMCMC<TData>::rnorm()
2581 {
2582  return rnormd->operator()(*m_engine);
2583 }
2584 
2585 template<typename TData>
2586 inline epiworld_double LFMCMC<TData>::rnorm(
2587  epiworld_double mean,
2588  epiworld_double sd
2589  )
2590 {
2591  return (rnormd->operator()(*m_engine)) * sd + mean;
2592 }
2593 
2594 template<typename TData>
2595 inline epiworld_double LFMCMC<TData>::rgamma()
2596 {
2597  return rgammad->operator()(*m_engine);
2598 }
2599 
2600 template<typename TData>
2601 inline epiworld_double LFMCMC<TData>::rgamma(
2602  epiworld_double alpha,
2603  epiworld_double beta
2604  )
2605 {
2606 
2607  auto old_param = rgammad->param();
2608 
2609  rgammad->param(std::gamma_distribution<>::param_type(alpha, beta));
2610 
2611  epiworld_double ans = rgammad->operator()(*m_engine);
2612 
2613  rgammad->param(old_param);
2614 
2615  return ans;
2616 
2617 }
2618 
2619 template<typename TData>
2620 inline void LFMCMC<TData>::seed(epiworld_fast_uint s) {
2621 
2622  this->m_engine->seed(s);
2623 
2624 }
2625 
2626 template<typename TData>
2627 inline void LFMCMC<TData>::set_rand_engine(std::shared_ptr< std::mt19937 > & eng)
2628 {
2629  m_engine = eng;
2630 }
2631 
2632 template<typename TData>
2633 inline void LFMCMC<TData>::set_rand_gamma(epiworld_double alpha, epiworld_double beta)
2634 {
2635  rgammad = std::make_shared<std::gamma_distribution<>>(alpha,beta);
2636 }
2637 
2638 template<typename TData>
2639 inline std::shared_ptr< std::mt19937 > & LFMCMC<TData>::get_rand_endgine()
2640 {
2641  return m_engine;
2642 }
2643 
2644 // Step 1: Simulate data
2645 
2646 // Step 2: Compute the sufficient statistics
2647 
2648 // Step 3: Compute the hastings-ratio
2649 
2650 // Step 4: Accept/reject, and go back to step 1
2651 
2652 #define DURCAST(tunit,txtunit) {\
2653  elapsed = std::chrono::duration_cast<std::chrono:: tunit>(\
2654  m_end_time - m_start_time).count(); \
2655  abbr_unit = txtunit;}
2656 
2657 template<typename TData>
2658 inline void LFMCMC<TData>::get_elapsed_time(
2659  std::string unit,
2660  epiworld_double * last_elapsed,
2661  std::string * unit_abbr,
2662  bool print
2663 ) const {
2664 
2665  // Preparing the result
2666  epiworld_double elapsed;
2667  std::string abbr_unit;
2668 
2669  // Figuring out the length
2670  if (unit == "auto")
2671  {
2672 
2673  size_t tlength = std::to_string(
2674  static_cast<int>(floor(m_elapsed_time.count()))
2675  ).length();
2676 
2677  if (tlength <= 1)
2678  unit = "nanoseconds";
2679  else if (tlength <= 3)
2680  unit = "microseconds";
2681  else if (tlength <= 6)
2682  unit = "milliseconds";
2683  else if (tlength <= 8)
2684  unit = "seconds";
2685  else if (tlength <= 9)
2686  unit = "minutes";
2687  else
2688  unit = "hours";
2689 
2690  }
2691 
2692  if (unit == "nanoseconds") DURCAST(nanoseconds,"ns")
2693  else if (unit == "microseconds") DURCAST(microseconds,"\xC2\xB5s")
2694  else if (unit == "milliseconds") DURCAST(milliseconds,"ms")
2695  else if (unit == "seconds") DURCAST(seconds,"s")
2696  else if (unit == "minutes") DURCAST(minutes,"m")
2697  else if (unit == "hours") DURCAST(hours,"h")
2698  else
2699  throw std::range_error("The time unit " + unit + " is not supported.");
2700 
2701 
2702  if (last_elapsed != nullptr)
2703  *last_elapsed = elapsed;
2704  if (unit_abbr != nullptr)
2705  *unit_abbr = abbr_unit;
2706 
2707  if (!print)
2708  return;
2709 
2710  printf_epiworld("Elapsed time : %.2f%s.\n", elapsed, abbr_unit.c_str());
2711 }
2712 
2713 #undef DURCAST
2714 
2715 /*//////////////////////////////////////////////////////////////////////////////
2717 
2718  Start of -include/epiworld/math/lfmcmc/lfmcmc-meat-print.hpp-
2719 
2722 
2723 
2724 #ifndef LFMCMC_MEAT_PRINT_HPP
2725 #define LFMCMC_MEAT_PRINT_HPP
2726 
2727 template<typename TData>
2728 inline void LFMCMC<TData>::print(size_t burnin) const
2729 {
2730 
2731  // For each statistic or parameter in the model, we print three values:
2732  // - mean, the 2.5% quantile, and the 97.5% quantile
2733  std::vector< epiworld_double > summ_params(m_n_params * 3, 0.0);
2734  std::vector< epiworld_double > summ_stats(m_n_stats * 3, 0.0);
2735 
2736  // Compute the number of samples to use based on burnin rate
2737  size_t n_samples_print = m_n_samples;
2738  if (burnin > 0)
2739  {
2740  if (burnin >= m_n_samples)
2741  throw std::length_error(
2742  "The burnin is greater than or equal to the number of samples."
2743  );
2744 
2745  n_samples_print = m_n_samples - burnin;
2746 
2747  }
2748 
2749  epiworld_double n_samples_dbl = static_cast< epiworld_double >(
2750  n_samples_print
2751  );
2752 
2753  // Compute parameter summary values
2754  for (size_t k = 0u; k < m_n_params; ++k)
2755  {
2756 
2757  // Retrieving the relevant parameter
2758  std::vector< epiworld_double > par_i(n_samples_print);
2759  for (size_t i = burnin; i < m_n_samples; ++i)
2760  {
2761  par_i[i-burnin] = m_all_accepted_params[i * m_n_params + k];
2762  summ_params[k * 3] += par_i[i-burnin]/n_samples_dbl;
2763  }
2764 
2765  // Computing the 95% Credible interval
2766  std::sort(par_i.begin(), par_i.end());
2767 
2768  summ_params[k * 3 + 1u] =
2769  par_i[std::floor(.025 * n_samples_dbl)];
2770  summ_params[k * 3 + 2u] =
2771  par_i[std::floor(.975 * n_samples_dbl)];
2772 
2773  }
2774 
2775  // Compute statistics summary values
2776  for (size_t k = 0u; k < m_n_stats; ++k)
2777  {
2778 
2779  // Retrieving the relevant parameter
2780  std::vector< epiworld_double > stat_k(n_samples_print);
2781  for (size_t i = burnin; i < m_n_samples; ++i)
2782  {
2783  stat_k[i-burnin] = m_all_accepted_stats[i * m_n_stats + k];
2784  summ_stats[k * 3] += stat_k[i-burnin]/n_samples_dbl;
2785  }
2786 
2787  // Computing the 95% Credible interval
2788  std::sort(stat_k.begin(), stat_k.end());
2789  summ_stats[k * 3 + 1u] =
2790  stat_k[std::floor(.025 * n_samples_dbl)];
2791  summ_stats[k * 3 + 2u] =
2792  stat_k[std::floor(.975 * n_samples_dbl)];
2793 
2794  }
2795 
2796  printf_epiworld("___________________________________________\n\n");
2797  printf_epiworld("LIKELIHOOD-FREE MARKOV CHAIN MONTE CARLO\n\n");
2798 
2799  printf_epiworld("N Samples (total) : %zu\n", m_n_samples);
2800  printf_epiworld("N Samples (after burn-in period) : %zu\n", m_n_samples - burnin);
2801 
2802  std::string abbr;
2803  epiworld_double elapsed;
2804  get_elapsed_time("auto", &elapsed, &abbr, false);
2805  printf_epiworld("Elapsed t : %.2f%s\n\n", elapsed, abbr.c_str());
2806 
2808  // PARAMETERS
2810  printf_epiworld("Parameters:\n");
2811 
2812  // Figuring out format
2813  std::string fmt_params;
2814 
2815  int nchar_par_num = 0;
2816  for (auto & n : summ_params)
2817  {
2818 
2819  int tmp_nchar;
2820 
2821  if (std::abs(n) < 1) {
2822  // std::log10(<1) will return negative number
2823  // std::log10(0) will return -inf and throw a runtime error
2824  tmp_nchar = 0;
2825  } else {
2826  tmp_nchar = std::floor(std::log10(std::abs(n)));
2827  }
2828 
2829  if (nchar_par_num < tmp_nchar)
2830  nchar_par_num = tmp_nchar;
2831  }
2832  nchar_par_num += 5; // 1 for neg padd, 2 for decimals, 1 the decimal point, and one b/c log(<10) < 1.
2833  std::string charlen = std::to_string(nchar_par_num);
2834 
2835  if (m_param_names.size() != 0u)
2836  {
2837  int nchar_par = 0;
2838  for (auto & n : m_param_names)
2839  {
2840  int tmp_nchar = n.length();
2841  if (nchar_par < tmp_nchar)
2842  nchar_par = tmp_nchar;
2843  }
2844 
2845  fmt_params = std::string(" -%-") +
2846  std::to_string(nchar_par) +
2847  std::string("s : % ") + charlen +
2848  std::string(".2f [% ") + charlen +
2849  std::string(".2f, % ") + charlen +
2850  std::string(".2f] (initial : % ") +
2851  charlen + std::string(".2f)\n");
2852 
2853  for (size_t k = 0u; k < m_n_params; ++k)
2854  {
2855  printf_epiworld(
2856  fmt_params.c_str(),
2857  m_param_names[k].c_str(),
2858  summ_params[k * 3],
2859  summ_params[k * 3 + 1u],
2860  summ_params[k * 3 + 2u],
2861  m_initial_params[k]
2862  );
2863  }
2864 
2865 
2866  } else {
2867 
2868  fmt_params = std::string(" [%-2ld]: % ") + charlen +
2869  std::string(".2f [% ") + charlen +
2870  std::string(".2f, % ") + charlen +
2871  std::string(".2f] (initial : % ") + charlen +
2872  std::string(".2f)\n");
2873 
2874  for (size_t k = 0u; k < m_n_params; ++k)
2875  {
2876 
2877  printf_epiworld(
2878  fmt_params.c_str(),
2879  k,
2880  summ_params[k * 3],
2881  summ_params[k * 3 + 1u],
2882  summ_params[k * 3 + 2u],
2883  m_initial_params[k]
2884  );
2885  }
2886 
2887  }
2888 
2890  // Statistics
2892  printf_epiworld("\nStatistics:\n");
2893  int nchar = 0;
2894  for (auto & s : summ_stats)
2895  {
2896  int tmp_nchar;
2897  if (std::abs(s) < 1) {
2898  // std::log10(<1) will return negative number
2899  // std::log10(0) will return -inf and throw a runtime error
2900  tmp_nchar = 0;
2901  } else {
2902  tmp_nchar = std::floor(std::log10(std::abs(s)));
2903  }
2904 
2905  if (nchar < tmp_nchar)
2906  nchar = tmp_nchar;
2907  }
2908 
2909  nchar += 5; // See above
2910 
2911  std::string nchar_char = std::to_string(nchar);
2912 
2913  // Figuring out format
2914  std::string fmt_stats;
2915  if (m_stat_names.size() != 0u)
2916  {
2917  int nchar_stats = 0;
2918  for (auto & n : m_stat_names)
2919  {
2920  int tmp_nchar = n.length();
2921  if (nchar_stats < tmp_nchar)
2922  nchar_stats = tmp_nchar;
2923  }
2924 
2925  fmt_stats = std::string(" -%-") +
2926  std::to_string(nchar_stats) +
2927  std::string("s : % ") + nchar_char +
2928  std::string(".2f [% ") + nchar_char +
2929  std::string(".2f, % ") + nchar_char +
2930  std::string(".2f] (Observed: % ") + nchar_char +
2931  std::string(".2f)\n");
2932 
2933  for (size_t k = 0u; k < m_n_stats; ++k)
2934  {
2935  printf_epiworld(
2936  fmt_stats.c_str(),
2937  m_stat_names[k].c_str(),
2938  summ_stats[k * 3],
2939  summ_stats[k * 3 + 1u],
2940  summ_stats[k * 3 + 2u],
2941  m_observed_stats[k]
2942  );
2943  }
2944 
2945 
2946  } else {
2947 
2948  fmt_stats = std::string(" [%-2ld] : % ") +
2949  nchar_char +
2950  std::string(".2f [% ") + nchar_char +
2951  std::string(".2f, % ") + nchar_char +
2952  std::string(".2f] (Observed: % ") + nchar_char +
2953  std::string(".2f)\n");
2954 
2955  for (size_t k = 0u; k < m_n_stats; ++k)
2956  {
2957  printf_epiworld(
2958  fmt_stats.c_str(),
2959  k,
2960  summ_stats[k * 3],
2961  summ_stats[k * 3 + 1u],
2962  summ_stats[k * 3 + 2u],
2963  m_observed_stats[k]
2964  );
2965  }
2966 
2967  }
2968 
2969  printf_epiworld("___________________________________________\n\n");
2970 }
2971 
2972 #endif
2973 /*//////////////////////////////////////////////////////////////////////////////
2975 
2976  End of -include/epiworld/math/lfmcmc/lfmcmc-meat-print.hpp-
2977 
2980 
2981 
2982 
2983 template<typename TData>
2984 inline void LFMCMC<TData>::chrono_start() {
2985  m_start_time = std::chrono::steady_clock::now();
2986 }
2987 
2988 template<typename TData>
2989 inline void LFMCMC<TData>::chrono_end() {
2990  m_end_time = std::chrono::steady_clock::now();
2991  m_elapsed_time += (m_end_time - m_start_time);
2992 }
2993 
2994 template<typename TData>
2995 inline void LFMCMC<TData>::set_params_names(std::vector< std::string > names)
2996 {
2997 
2998  if (names.size() != m_n_params)
2999  throw std::length_error("The number of names to add differs from the number of parameters in the model.");
3000 
3001  m_param_names = names;
3002 
3003 }
3004 template<typename TData>
3005 inline void LFMCMC<TData>::set_stats_names(std::vector< std::string > names)
3006 {
3007 
3008  if (names.size() != m_n_stats)
3009  throw std::length_error("The number of names to add differs from the number of statistics in the model.");
3010 
3011  m_stat_names = names;
3012 
3013 }
3014 
3015 template<typename TData>
3016 inline std::vector< epiworld_double > LFMCMC<TData>::get_mean_params()
3017 {
3018  std::vector< epiworld_double > res(this->m_n_params, 0.0);
3019 
3020  for (size_t k = 0u; k < m_n_params; ++k)
3021  {
3022  for (size_t i = 0u; i < m_n_samples; ++i)
3023  res[k] += (this->m_all_accepted_params[k + m_n_params * i])/
3024  static_cast< epiworld_double >(m_n_samples);
3025  }
3026 
3027  return res;
3028 
3029 }
3030 
3031 template<typename TData>
3032 inline std::vector< epiworld_double > LFMCMC<TData>::get_mean_stats()
3033 {
3034  std::vector< epiworld_double > res(this->m_n_stats, 0.0);
3035 
3036  for (size_t k = 0u; k < m_n_stats; ++k)
3037  {
3038  for (size_t i = 0u; i < m_n_samples; ++i)
3039  res[k] += (this->m_all_accepted_stats[k + m_n_stats * i])/
3040  static_cast< epiworld_double >(m_n_samples);
3041  }
3042 
3043  return res;
3044 
3045 }
3046 
3047 template<typename TData>
3048 inline LFMCMC<TData> & LFMCMC<TData>::verbose_off()
3049 {
3050  verbose = false;
3051  return *this;
3052 }
3053 
3054 template<typename TData>
3055 inline LFMCMC<TData> & LFMCMC<TData>::verbose_on()
3056 {
3057  verbose = true;
3058  return *this;
3059 }
3060 
3061 #endif
3062 /*//////////////////////////////////////////////////////////////////////////////
3064 
3065  End of -include/epiworld/math/lfmcmc/lfmcmc-meat.hpp-
3066 
3069 
3070 
3071 
3072 #endif
3073 /*//////////////////////////////////////////////////////////////////////////////
3075 
3076  End of -include/epiworld/math/lfmcmc.hpp-
3077 
3080 
3081 
3082 
3083 /*//////////////////////////////////////////////////////////////////////////////
3085 
3086  Start of -include/epiworld/userdata-bones.hpp-
3087 
3090 
3091 
3092 #ifndef EPIWORLD_USERDATA_BONES_HPP
3093 #define EPIWORLD_USERDATA_BONES_HPP
3094 
3095 template<typename TSeq>
3096 class Model;
3097 
3098 template<typename TSeq>
3099 class DataBase;
3100 
3106 template<typename TSeq>
3107 class UserData
3108 {
3109  friend class Model<TSeq>;
3110  friend class DataBase<TSeq>;
3111 
3112 private:
3113  Model<TSeq> * model;
3114 
3115  std::vector< std::string > data_names;
3116  std::vector< int > data_dates;
3117  std::vector< epiworld_double > data_data;
3118 
3119  epiworld_fast_uint k = 0u;
3120  epiworld_fast_uint n = 0u;
3121 
3122  int last_day = -1;
3123 
3124 public:
3125 
3126  UserData() = delete;
3127  UserData(Model<TSeq> & m) : model(&m) {};
3128  UserData(Model<TSeq> * m) : model(m) {};
3129 
3136  UserData(std::vector< std::string > names);
3137 
3145  void add(std::vector<epiworld_double> x);
3146  void add(
3147  epiworld_fast_uint j,
3148  epiworld_double x
3149  );
3151 
3160  epiworld_double & operator()(
3161  epiworld_fast_uint i,
3162  epiworld_fast_uint j
3163  );
3164 
3165  epiworld_double & operator()(
3166  epiworld_fast_uint i,
3167  std::string name
3168  );
3170 
3171  std::vector< std::string > & get_names();
3172 
3173  std::vector< int > & get_dates();
3174 
3175  std::vector< epiworld_double > & get_data();
3176 
3177  void get_all(
3178  std::vector< std::string > * names = nullptr,
3179  std::vector< int > * date = nullptr,
3180  std::vector< epiworld_double > * data = nullptr
3181  );
3182 
3183  epiworld_fast_uint nrow() const;
3184  epiworld_fast_uint ncol() const;
3185 
3186  void write(std::string fn);
3187  void print() const;
3188 
3189 };
3190 
3191 #endif
3192 /*//////////////////////////////////////////////////////////////////////////////
3194 
3195  End of -include/epiworld/userdata-bones.hpp-
3196 
3199 
3200 
3201 /*//////////////////////////////////////////////////////////////////////////////
3203 
3204  Start of -include/epiworld/userdata-meat.hpp-
3205 
3208 
3209 
3210 #ifndef EPIWORLD_USERDATA_MEAT_HPP
3211 #define EPIWORLD_USERDATA_MEAT_HPP
3212 
3213 template<typename TSeq>
3214 class UserData;
3215 
3216 template<typename TSeq>
3217 inline UserData<TSeq>::UserData(std::vector< std::string > names)
3218 {
3219 
3220  k = names.size();
3221  data_names = names;
3222 
3223 }
3224 
3225 template<typename TSeq>
3226 inline void UserData<TSeq>::add(std::vector<epiworld_double> x)
3227 {
3228 
3229  if (x.size() != k)
3230  throw std::out_of_range(
3231  "The size of -x-, " + std::to_string(x.size()) + ", does not match " +
3232  "the number of elements registered (" + std::to_string(k));
3233 
3234  for (auto & i : x)
3235  data_data.push_back(i);
3236 
3237  data_dates.push_back(model->today());
3238 
3239  n++;
3240  last_day = model->today();
3241 
3242 }
3243 
3244 template<typename TSeq>
3245 inline void UserData<TSeq>::add(epiworld_fast_uint j, epiworld_double x)
3246 {
3247 
3248  // Starting with a new day?
3249  if (static_cast<int>(model->today()) != last_day)
3250  {
3251 
3252  std::vector< epiworld_double > tmp(k, 0.0);
3253 
3254  tmp[j] = x;
3255 
3256  add(tmp);
3257 
3258  }
3259  else
3260  {
3261 
3262  this->operator()(n - 1, j) = x;
3263 
3264  }
3265 
3266 }
3267 
3268 template<typename TSeq>
3269 inline std::vector< std::string > & UserData<TSeq>::get_names()
3270 {
3271  return data_names;
3272 }
3273 
3274 template<typename TSeq>
3275 inline std::vector< int > & UserData<TSeq>::get_dates()
3276 {
3277  return data_dates;
3278 }
3279 
3280 template<typename TSeq>
3281 inline std::vector< epiworld_double > & UserData<TSeq>::get_data()
3282 {
3283  return data_data;
3284 }
3285 
3286 template<typename TSeq>
3287 inline void UserData<TSeq>::get_all(
3288  std::vector< std::string > * names,
3289  std::vector< int > * date,
3290  std::vector< epiworld_double > * data
3291 )
3292 {
3293 
3294  if (names != nullptr)
3295  names = &this->data_names;
3296 
3297  if (date != nullptr)
3298  date = &this->data_dates;
3299 
3300  if (data != nullptr)
3301  data = &this->data_data;
3302 
3303 }
3304 
3305 template<typename TSeq>
3306 inline epiworld_double & UserData<TSeq>::operator()(
3307  epiworld_fast_uint i,
3308  epiworld_fast_uint j
3309 )
3310 {
3311 
3312  if (j >= k)
3313  throw std::out_of_range("j cannot be greater than k - 1.");
3314 
3315  if (i >= n)
3316  throw std::out_of_range("j cannot be greater than n - 1.");
3317 
3318  return data_data[k * i + j];
3319 
3320 }
3321 
3322 template<typename TSeq>
3323 inline epiworld_double & UserData<TSeq>::operator()(
3324  epiworld_fast_uint i,
3325  std::string name
3326 )
3327 {
3328  int loc = -1;
3329  for (epiworld_fast_uint l = 0u; l < k; ++l)
3330  {
3331 
3332  if (name == data_names[l])
3333  {
3334 
3335  loc = l;
3336  break;
3337 
3338  }
3339 
3340  }
3341 
3342  if (loc < 0)
3343  throw std::range_error(
3344  "The variable \"" + name + "\" is not present " +
3345  "in the user UserData database."
3346  );
3347 
3348  return operator()(i, static_cast<epiworld_fast_uint>(loc));
3349 
3350 }
3351 
3352 template<typename TSeq>
3353 inline epiworld_fast_uint UserData<TSeq>::nrow() const
3354 {
3355  return n;
3356 }
3357 
3358 template<typename TSeq>
3359 inline epiworld_fast_uint UserData<TSeq>::ncol() const
3360 {
3361  return k;
3362 }
3363 
3364 template<typename TSeq>
3365 inline void UserData<TSeq>::write(std::string fn)
3366 {
3367  std::ofstream file_ud(fn, std::ios_base::out);
3368 
3369  // File header
3370  file_ud << "\"date\"";
3371  for (auto & cn : data_names)
3372  file_ud << " \"" + cn + "\"";
3373  file_ud << "\n";
3374 
3375  epiworld_fast_uint ndata = 0u;
3376  for (epiworld_fast_uint i = 0u; i < n; ++i)
3377  {
3378  file_ud << data_dates[i];
3379 
3380  for (epiworld_fast_uint j = 0u; j < k; ++j)
3381  file_ud << " " << data_data[ndata++];
3382 
3383  file_ud << "\n";
3384  }
3385 
3386  return;
3387 }
3388 
3389 template<typename TSeq>
3390 inline void UserData<TSeq>::print() const
3391 {
3392  // File header
3393  printf_epiworld("Total records: %llu\n", n);
3394  printf_epiworld("date");
3395 
3396  for (auto & cn : data_names)
3397  {
3398 
3399  printf_epiworld(" %s", cn.c_str());
3400 
3401  }
3402 
3403  printf_epiworld("\n");
3404 
3405  epiworld_fast_uint ndata = 0u;
3406 
3407  for (epiworld_fast_uint i = 0u; i < n; ++i)
3408  {
3409 
3410  printf_epiworld("%i", data_dates[i]);
3411 
3412  for (epiworld_fast_uint j = 0u; j < k; ++j)
3413  {
3414 
3415  printf_epiworld(" %.2f", data_data[ndata++]);
3416 
3417  }
3418 
3419  printf_epiworld("\n");
3420 
3421  }
3422 
3423  return;
3424 }
3425 
3426 #endif
3427 /*//////////////////////////////////////////////////////////////////////////////
3429 
3430  End of -include/epiworld/userdata-meat.hpp-
3431 
3434 
3435 
3436 
3437 /*//////////////////////////////////////////////////////////////////////////////
3439 
3440  Start of -include/epiworld/seq_processing.hpp-
3441 
3444 
3445 
3446 #ifndef EPIWORLD_SEQ_PROCESSING_HPP
3447 #define EPIWORLD_SEQ_PROCESSING_HPP
3448 
3456 template<typename TSeq>
3457 inline std::vector<int> default_seq_hasher(const TSeq & x);
3458 
3459 template<>
3460 inline std::vector<int> default_seq_hasher<std::vector<int>>(const std::vector<int> & x) {
3461  return x;
3462 }
3463 
3464 template<>
3465 inline std::vector<int> default_seq_hasher<std::vector<bool>>(const std::vector<bool> & x) {
3466  std::vector<int> ans(x.size());
3467  size_t j = 0;
3468  for (const auto & i : x)
3469  ans[j++] = i? 1 : 0;
3470  return ans;
3471 }
3472 
3473 template<>
3474 inline std::vector<int> default_seq_hasher<int>(const int & x) {
3475  return {x};
3476 }
3477 
3478 template<>
3479 inline std::vector<int> default_seq_hasher<bool>(const bool & x) {
3480  return {x ? 1 : 0};
3481 }
3482 
3490 template<typename TSeq = EPI_DEFAULT_TSEQ>
3491 inline std::string default_seq_writer(const TSeq & seq);
3492 
3493 template<>
3494 inline std::string default_seq_writer<std::vector<int>>(
3495  const std::vector<int> & seq
3496 ) {
3497 
3498  std::string out = "";
3499  for (const auto & s : seq)
3500  out = out + std::to_string(s);
3501 
3502  return out;
3503 
3504 }
3505 
3506 template<>
3507 inline std::string default_seq_writer<std::vector<bool>>(
3508  const std::vector<bool> & seq
3509 ) {
3510 
3511  std::string out = "";
3512  for (const auto & s : seq)
3513  out = out + (s ? "1" : "0");
3514 
3515  return out;
3516 
3517 }
3518 
3519 template<>
3520 inline std::string default_seq_writer<bool>(
3521  const bool & seq
3522 ) {
3523 
3524  return seq ? "1" : "0";
3525 
3526 }
3527 
3528 template<>
3529 inline std::string default_seq_writer<int>(
3530  const int & seq
3531 ) {
3532 
3533  return std::to_string(seq);
3534 
3535 }
3536 
3537 
3538 
3539 #endif
3540 /*//////////////////////////////////////////////////////////////////////////////
3542 
3543  End of -include/epiworld/seq_processing.hpp-
3544 
3547 
3548 
3549 
3550 /*//////////////////////////////////////////////////////////////////////////////
3552 
3553  Start of -include/epiworld/database-bones.hpp-
3554 
3557 
3558 
3559 #ifndef EPIWORLD_DATABASE_BONES_HPP
3560 #define EPIWORLD_DATABASE_BONES_HPP
3561 
3562 template<typename TSeq>
3563 class Model;
3564 
3565 template<typename TSeq>
3566 class Virus;
3567 
3568 template<typename TSeq>
3569 class UserData;
3570 
3571 template<typename TSeq>
3572 inline void default_add_virus(Event<TSeq> & a, Model<TSeq> * m);
3573 
3574 template<typename TSeq>
3575 inline void default_add_tool(Event<TSeq> & a, Model<TSeq> * m);
3576 
3577 template<typename TSeq>
3578 inline void default_rm_virus(Event<TSeq> & a, Model<TSeq> * m);
3579 
3580 template<typename TSeq>
3581 inline void default_rm_tool(Event<TSeq> & a, Model<TSeq> * m);
3582 
3583 template<typename TSeq>
3584 inline void default_change_state(Event<TSeq> & a, Model<TSeq> * m);
3585 
3591 template<typename TSeq>
3592 class DataBase {
3593  friend class Model<TSeq>;
3594  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
3595  friend void default_add_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
3596  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
3597  friend void default_rm_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
3598  friend void default_change_state<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
3599 private:
3600  Model<TSeq> * model;
3601 
3602  // Variants information
3603  MapVec_type<int,int> virus_id; ///< The squence is the key
3604  std::vector< std::string > virus_name;
3605  std::vector< TSeq> virus_sequence;
3606  std::vector< int > virus_origin_date;
3607  std::vector< int > virus_parent_id;
3608 
3609  MapVec_type<int,int> tool_id; ///< The squence is the key
3610  std::vector< std::string > tool_name;
3611  std::vector< TSeq> tool_sequence;
3612  std::vector< int > tool_origin_date;
3613 
3614  std::function<std::vector<int>(const TSeq&)> seq_hasher = default_seq_hasher<TSeq>;
3615  std::function<std::string(const TSeq &)> seq_writer = default_seq_writer<TSeq>;
3616 
3617  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
3618  std::vector< std::vector<int> > today_virus;
3619 
3620  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
3621  std::vector< std::vector<int> > today_tool;
3622 
3623  // {Susceptible, Infected, etc.}
3624  std::vector< int > today_total;
3625 
3626  // Totals
3627  int today_total_nviruses_active = 0;
3628 
3629  int sampling_freq = 1;
3630 
3631  // Variants history
3632  std::vector< int > hist_virus_date;
3633  std::vector< int > hist_virus_id;
3634  std::vector< epiworld_fast_uint > hist_virus_state;
3635  std::vector< int > hist_virus_counts;
3636 
3637  // Tools history
3638  std::vector< int > hist_tool_date;
3639  std::vector< int > hist_tool_id;
3640  std::vector< epiworld_fast_uint > hist_tool_state;
3641  std::vector< int > hist_tool_counts;
3642 
3643  // Overall hist
3644  std::vector< int > hist_total_date;
3645  std::vector< int > hist_total_nviruses_active;
3646  std::vector< epiworld_fast_uint > hist_total_state;
3647  std::vector< int > hist_total_counts;
3648  std::vector< int > hist_transition_matrix;
3649 
3650  // Transmission network
3651  std::vector< int > transmission_date; ///< Date of the transmission event
3652  std::vector< int > transmission_source; ///< Id of the source
3653  std::vector< int > transmission_target; ///< Id of the target
3654  std::vector< int > transmission_virus; ///< Id of the variant
3655  std::vector< int > transmission_source_exposure_date; ///< Date when the source acquired the variant
3656 
3657  std::vector< int > transition_matrix;
3658 
3659  UserData<TSeq> user_data;
3660 
3661  void update_state(
3662  epiworld_fast_uint prev_state,
3663  epiworld_fast_uint new_state,
3664  bool undo = false
3665  );
3666 
3667  void update_virus(
3668  epiworld_fast_uint virus_id,
3669  epiworld_fast_uint prev_state,
3670  epiworld_fast_uint new_state
3671  );
3672 
3673  void update_tool(
3674  epiworld_fast_uint tool_id,
3675  epiworld_fast_uint prev_state,
3676  epiworld_fast_uint new_state
3677  );
3678 
3679  void record_transition(epiworld_fast_uint from, epiworld_fast_uint to, bool undo);
3680 
3681 
3682 public:
3683 
3684  #ifdef EPI_DEBUG
3685  int n_transmissions_potential = 0;
3686  int n_transmissions_today = 0;
3687  #endif
3688 
3689  DataBase() = delete;
3690  DataBase(Model<TSeq> & m) : model(&m), user_data(m) {};
3691  DataBase(const DataBase<TSeq> & db);
3692  // DataBase<TSeq> & operator=(const DataBase<TSeq> & m);
3693 
3702  void record_virus(Virus<TSeq> & v);
3703  void record_tool(Tool<TSeq> & t);
3704  void set_seq_hasher(std::function<std::vector<int>(TSeq)> fun);
3705  void reset();
3706  Model<TSeq> * get_model();
3707  void record();
3708 
3709  const std::vector< TSeq > & get_sequence() const;
3710  const std::vector< int > & get_nexposed() const;
3711  size_t size() const;
3712 
3726  int get_today_total(const std::string & what) const;
3727  int get_today_total(const epiworld_fast_uint & what) const;
3728  void get_today_total(
3729  std::vector< std::string > * state = nullptr,
3730  std::vector< int > * counts = nullptr
3731  ) const;
3732 
3733  void get_today_virus(
3734  std::vector< std::string > & state,
3735  std::vector< int > & id,
3736  std::vector< int > & counts
3737  ) const;
3738 
3739  void get_today_transition_matrix(
3740  std::vector< int > & counts
3741  ) const;
3742 
3743  void get_hist_total(
3744  std::vector< int > * date,
3745  std::vector< std::string > * state,
3746  std::vector< int > * counts
3747  ) const;
3748 
3749  void get_hist_virus(
3750  std::vector< int > & date,
3751  std::vector< int > & id,
3752  std::vector< std::string > & state,
3753  std::vector< int > & counts
3754  ) const;
3755 
3756  void get_hist_tool(
3757  std::vector< int > & date,
3758  std::vector< int > & id,
3759  std::vector< std::string > & state,
3760  std::vector< int > & counts
3761  ) const;
3762 
3763  void get_hist_transition_matrix(
3764  std::vector< std::string > & state_from,
3765  std::vector< std::string > & state_to,
3766  std::vector< int > & date,
3767  std::vector< int > & counts,
3768  bool skip_zeros
3769  ) const;
3771 
3782  void get_transmissions(
3783  std::vector<int> & date,
3784  std::vector<int> & source,
3785  std::vector<int> & target,
3786  std::vector<int> & virus,
3787  std::vector<int> & source_exposure_date
3788  ) const;
3789 
3790  void get_transmissions(
3791  int * date,
3792  int * source,
3793  int * target,
3794  int * virus,
3795  int * source_exposure_date
3796  ) const;
3798 
3799  void write_data(
3800  std::string fn_virus_info,
3801  std::string fn_virus_hist,
3802  std::string fn_tool_info,
3803  std::string fn_tool_hist,
3804  std::string fn_total_hist,
3805  std::string fn_transmission,
3806  std::string fn_transition,
3807  std::string fn_reproductive_number,
3808  std::string fn_generation_time
3809  ) const;
3810 
3811  /***
3812  * @brief Record a transmission event
3813  * @param i,j Integers. Id of the source and target agents.
3814  * @param virus Integer. Id of the virus.
3815  * @param i_expo_date Integer. Date when the source agent was infected.
3816  * @details
3817  * If i is -1, then it means that the agent was assigned a virus at the
3818  * beginning of the simulation.
3819  */
3820  void record_transmission(int i, int j, int virus, int i_expo_date);
3821 
3822  size_t get_n_viruses() const;
3823  size_t get_n_tools() const;
3824 
3825  void set_user_data(std::vector< std::string > names);
3826  void add_user_data(std::vector< epiworld_double > x);
3827  void add_user_data(epiworld_fast_uint j, epiworld_double x);
3828  UserData<TSeq> & get_user_data();
3829 
3830 
3846  MapVec_type<int,int> get_reproductive_number() const;
3847 
3848  void get_reproductive_number(
3849  std::string fn
3850  ) const;
3852 
3866  std::vector< epiworld_double > get_transition_probability(
3867  bool print = true,
3868  bool normalize = true
3869  ) const;
3870 
3871  bool operator==(const DataBase<TSeq> & other) const;
3872  bool operator!=(const DataBase<TSeq> & other) const {return !operator==(other);};
3873 
3883  void get_generation_time(
3884  std::vector< int > & agent_id,
3885  std::vector< int > & virus_id,
3886  std::vector< int > & time,
3887  std::vector< int > & gentime
3888  ) const;
3889 
3890  void get_generation_time(
3891  std::string fn
3892  ) const;
3894 
3895 };
3896 
3897 
3898 #endif
3899 /*//////////////////////////////////////////////////////////////////////////////
3901 
3902  End of -include/epiworld/database-bones.hpp-
3903 
3906 
3907 
3908 /*//////////////////////////////////////////////////////////////////////////////
3910 
3911  Start of -include/epiworld/database-meat.hpp-
3912 
3915 
3916 
3917 #ifndef EPIWORLD_DATABASE_MEAT_HPP
3918 #define EPIWORLD_DATABASE_MEAT_HPP
3919 
3920 #include <vector>
3921 #include <string>
3922 /*//////////////////////////////////////////////////////////////////////////////
3924 
3925  Start of -include/epiworld/config.hpp-
3926 
3929 
3930 
3931 #ifndef EPIWORLD_CONFIG_HPP
3932 #define EPIWORLD_CONFIG_HPP
3933 
3934 #ifndef printf_epiworld
3935  #define printf_epiworld fflush(stdout);printf
3936 #endif
3937 
3938 // In case the user has a way to stop the program
3939 // This is called during `run_multiple()` and it is
3940 // passed the simulation number.
3941 #ifndef EPI_CHECK_USER_INTERRUPT
3942  #define EPI_CHECK_USER_INTERRUPT(a)
3943 #endif
3944 
3945 #ifndef EPIWORLD_MAXNEIGHBORS
3946  #define EPIWORLD_MAXNEIGHBORS 1048576
3947 #endif
3948 
3949 #if defined(_OPENMP) || defined(__OPENMP)
3950  #include <omp.h>
3951 // #else
3952 // #define omp_get_thread_num() 0
3953 // #define omp_set_num_threads() 1
3954 #endif
3955 
3956 #ifndef epiworld_double
3957  #define epiworld_double float
3958 #endif
3959 
3960 #ifndef epiworld_fast_int
3961  #define epiworld_fast_int int
3962 #endif
3963 
3964 #ifndef epiworld_fast_uint
3965  #define epiworld_fast_uint unsigned long long int
3966 #endif
3967 
3968 #define EPI_DEFAULT_TSEQ int
3969 
3970 #ifndef EPI_MAX_TRACKING
3971  #define EPI_MAX_TRACKING 200
3972 #endif
3973 
3974 template<typename TSeq = EPI_DEFAULT_TSEQ>
3975 class Model;
3976 
3977 template<typename TSeq = EPI_DEFAULT_TSEQ>
3978 class Agent;
3979 
3980 template<typename TSeq = EPI_DEFAULT_TSEQ>
3981 class PersonTools;
3982 
3983 template<typename TSeq = EPI_DEFAULT_TSEQ>
3984 class Virus;
3985 
3986 template<typename TSeq = EPI_DEFAULT_TSEQ>
3987 class Viruses;
3988 
3989 template<typename TSeq = EPI_DEFAULT_TSEQ>
3990 class Viruses_const;
3991 
3992 template<typename TSeq = EPI_DEFAULT_TSEQ>
3993 class Tool;
3994 
3995 template<typename TSeq = EPI_DEFAULT_TSEQ>
3996 class Tools;
3997 
3998 template<typename TSeq = EPI_DEFAULT_TSEQ>
3999 class Tools_const;
4000 
4001 template<typename TSeq = EPI_DEFAULT_TSEQ>
4002 class Entity;
4003 
4004 template<typename TSeq = EPI_DEFAULT_TSEQ>
4005 using VirusPtr = std::shared_ptr< Virus< TSeq > >;
4006 
4007 template<typename TSeq = EPI_DEFAULT_TSEQ>
4008 using ToolPtr = std::shared_ptr< Tool< TSeq > >;
4009 
4010 template<typename TSeq = EPI_DEFAULT_TSEQ>
4011 using ToolFun = std::function<epiworld_double(Tool<TSeq>&,Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
4012 
4013 template<typename TSeq = EPI_DEFAULT_TSEQ>
4014 using MixerFun = std::function<epiworld_double(Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
4015 
4016 template<typename TSeq = EPI_DEFAULT_TSEQ>
4017 using MutFun = std::function<bool(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
4018 
4019 template<typename TSeq = EPI_DEFAULT_TSEQ>
4020 using PostRecoveryFun = std::function<void(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
4021 
4022 template<typename TSeq = EPI_DEFAULT_TSEQ>
4023 using VirusFun = std::function<epiworld_double(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
4024 
4025 template<typename TSeq = EPI_DEFAULT_TSEQ>
4026 using UpdateFun = std::function<void(Agent<TSeq>*,Model<TSeq>*)>;
4027 
4028 template<typename TSeq = EPI_DEFAULT_TSEQ>
4029 using GlobalFun = std::function<void(Model<TSeq>*)>;
4030 
4031 template<typename TSeq>
4032 struct Event;
4033 
4034 template<typename TSeq = EPI_DEFAULT_TSEQ>
4035 using EventFun = std::function<void(Event<TSeq>&,Model<TSeq>*)>;
4036 
4040 template<typename TSeq = EPI_DEFAULT_TSEQ>
4041 using VirusToAgentFun = std::function<void(Virus<TSeq>&,Model<TSeq>*)>;
4042 
4046 template<typename TSeq = EPI_DEFAULT_TSEQ>
4047 using ToolToAgentFun = std::function<void(Tool<TSeq>&,Model<TSeq>*)>;
4048 
4052 template<typename TSeq = EPI_DEFAULT_TSEQ>
4053 using EntityToAgentFun = std::function<void(Entity<TSeq>&,Model<TSeq>*)>;
4054 
4060 template<typename TSeq = EPI_DEFAULT_TSEQ>
4061 struct Event {
4062  Agent<TSeq> * agent;
4063  VirusPtr<TSeq> virus;
4064  ToolPtr<TSeq> tool;
4065  Entity<TSeq> * entity;
4066  epiworld_fast_int new_state;
4067  epiworld_fast_int queue;
4068  EventFun<TSeq> call;
4069  int idx_agent;
4070  int idx_object;
4071 public:
4088  Event(
4089  Agent<TSeq> * agent_,
4090  VirusPtr<TSeq> & virus_,
4091  ToolPtr<TSeq> & tool_,
4092  Entity<TSeq> * entity_,
4093  epiworld_fast_int new_state_,
4094  epiworld_fast_int queue_,
4095  EventFun<TSeq> & call_,
4096  int idx_agent_,
4097  int idx_object_
4098  ) : agent(agent_), virus(virus_), tool(tool_), entity(entity_),
4099  new_state(new_state_),
4100  queue(queue_), call(call_), idx_agent(idx_agent_), idx_object(idx_object_) {
4101  return;
4102  };
4103 };
4104 
4112 #ifndef DEFAULT_TOOL_CONTAGION_REDUCTION
4113  #define DEFAULT_TOOL_CONTAGION_REDUCTION 0.0
4114 #endif
4115 
4116 #ifndef DEFAULT_TOOL_TRANSMISSION_REDUCTION
4117  #define DEFAULT_TOOL_TRANSMISSION_REDUCTION 0.0
4118 #endif
4119 
4120 #ifndef DEFAULT_TOOL_RECOVERY_ENHANCER
4121  #define DEFAULT_TOOL_RECOVERY_ENHANCER 0.0
4122 #endif
4123 
4124 #ifndef DEFAULT_TOOL_DEATH_REDUCTION
4125  #define DEFAULT_TOOL_DEATH_REDUCTION 0.0
4126 #endif
4127 
4128 #ifndef EPI_DEFAULT_VIRUS_PROB_INFECTION
4129  #define EPI_DEFAULT_VIRUS_PROB_INFECTION 1.0
4130 #endif
4131 
4132 #ifndef EPI_DEFAULT_VIRUS_PROB_RECOVERY
4133  #define EPI_DEFAULT_VIRUS_PROB_RECOVERY 0.1428
4134 #endif
4135 
4136 #ifndef EPI_DEFAULT_VIRUS_PROB_DEATH
4137  #define EPI_DEFAULT_VIRUS_PROB_DEATH 0.0
4138 #endif
4139 
4140 #ifndef EPI_DEFAULT_INCUBATION_DAYS
4141  #define EPI_DEFAULT_INCUBATION_DAYS 7.0
4142 #endif
4144 
4145 #ifdef EPI_DEBUG
4146  #define EPI_DEBUG_PRINTF printf_epiworld
4147 
4148  #define EPI_DEBUG_ERROR(etype, msg) \
4149  (etype)("[[epi-debug]] (error) " + std::string(msg));
4150 
4151  #define EPI_DEBUG_NOTIFY_ACTIVE() \
4152  EPI_DEBUG_PRINTF("DEBUGGING ON (compiled with EPI_DEBUG defined)%s\n", "");
4153 
4154  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect) \
4155  for (auto & v : vect) \
4156  if (static_cast<double>(v) < 0.0) \
4157  throw EPI_DEBUG_ERROR(std::logic_error, "A negative value not allowed.");
4158 
4159  #define EPI_DEBUG_SUM_DBL(vect, num) \
4160  double _epi_debug_sum = 0.0; \
4161  for (auto & v : vect) \
4162  { \
4163  _epi_debug_sum += static_cast<double>(v);\
4164  if (_epi_debug_sum > static_cast<double>(num)) \
4165  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
4166  }
4167 
4168  #define EPI_DEBUG_SUM_INT(vect, num) \
4169  int _epi_debug_sum = 0; \
4170  for (auto & v : vect) \
4171  { \
4172  _epi_debug_sum += static_cast<int>(v);\
4173  if (_epi_debug_sum > static_cast<int>(num)) \
4174  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
4175  }
4176 
4177  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c) \
4178  if (a.size() != b.size()) {\
4179  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
4180  EPI_DEBUG_PRINTF("Size of vector a: %lu\n", (a).size());\
4181  EPI_DEBUG_PRINTF("Size of vector b: %lu\n", (b).size());\
4182  throw EPI_DEBUG_ERROR(std::length_error, "The vectors do not match size."); \
4183  }\
4184  for (int _i = 0; _i < static_cast<int>(a.size()); ++_i) \
4185  if (a[_i] != b[_i]) {\
4186  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
4187  EPI_DEBUG_PRINTF("Iterating the last 5 values%s:\n", ""); \
4188  for (int _j = std::max(0, static_cast<int>(_i) - 4); _j <= _i; ++_j) \
4189  { \
4190  EPI_DEBUG_PRINTF( \
4191  "a[%i]: %i; b[%i]: %i\n", \
4192  _j, \
4193  static_cast<int>(a[_j]), \
4194  _j, static_cast<int>(b[_j])); \
4195  } \
4196  throw EPI_DEBUG_ERROR(std::logic_error, "The vectors do not match."); \
4197  }
4198 
4199  #define EPI_DEBUG_FAIL_AT_TRUE(a,b) \
4200  if (a) \
4201  {\
4202  throw EPI_DEBUG_ERROR(std::logic_error, b); \
4203  }
4204 
4205  #define epiexception(a) std::logic_error
4206 #else
4207  #define EPI_DEBUG_PRINTF(fmt, ...)
4208  #define EPI_DEBUG_ERROR(fmt, ...)
4209  #define EPI_DEBUG_NOTIFY_ACTIVE()
4210  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect)
4211  #define EPI_DEBUG_SUM_DBL(vect, num)
4212  #define EPI_DEBUG_SUM_INT(vect, num)
4213  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c)
4214  #define EPI_DEBUG_FAIL_AT_TRUE(a, b) \
4215  if (a) \
4216  return false;
4217  #define epiexception(a) a
4218 #endif
4219 
4220 #if defined(EPI_DEBUG_NO_THREAD_ID) || (!defined(__OPENMP) && !defined(_OPENMP))
4221  #define EPI_GET_THREAD_ID() 0
4222 #else
4223  #define EPI_GET_THREAD_ID() omp_get_thread_num()
4224 #endif
4225 
4226 #endif
4227 /*//////////////////////////////////////////////////////////////////////////////
4229 
4230  End of -include/epiworld/config.hpp-
4231 
4234 
4235 
4236 /*//////////////////////////////////////////////////////////////////////////////
4238 
4239  Start of -include/epiworld/epiworld-macros.hpp-
4240 
4243 
4244 
4245 #ifndef EPIWORLD_MACROS_HPP
4246 #define EPIWORLD_MACROS_HPP
4247 
4252 #define EPI_NEW_TOOL(fname,tseq) inline epiworld_double \
4253 (fname)(\
4254  epiworld::Tool< tseq > & t, \
4255  epiworld::Agent< tseq > * p, \
4256  std::shared_ptr<epiworld::Virus< tseq >> v, \
4257  epiworld::Model< tseq > * m\
4258  )
4259 
4264 #define EPI_NEW_TOOL_LAMBDA(funname,tseq) \
4265  epiworld::ToolFun<tseq> funname = \
4266  [](epiworld::Tool<tseq> & t, \
4267  epiworld::Agent<tseq> * p, \
4268  std::shared_ptr<epiworld::Virus<tseq>> v, \
4269  epiworld::Model<tseq> * m) -> epiworld_double
4270 
4275 #define EPI_PARAMS(i) m->operator()(i)
4276 
4281 #define EPI_NEW_MUTFUN(funname,tseq) inline bool \
4282  (funname)(\
4283  epiworld::Agent<tseq> * p, \
4284  epiworld::Virus<tseq> & v, \
4285  epiworld::Model<tseq> * m )
4286 
4287 #define EPI_NEW_MUTFUN_LAMBDA(funname,tseq) \
4288  epiworld::MutFun<tseq> funname = \
4289  [](epiworld::Agent<tseq> * p, \
4290  epiworld::Virus<tseq> & v, \
4291  epiworld::Model<tseq> * m) -> void
4292 
4293 #define EPI_NEW_POSTRECOVERYFUN(funname,tseq) inline void \
4294  (funname)( \
4295  epiworld::Agent<tseq> * p, \
4296  epiworld::Virus<tseq> & v, \
4297  epiworld::Model<tseq> * m\
4298  )
4299 
4300 #define EPI_NEW_POSTRECOVERYFUN_LAMBDA(funname,tseq) \
4301  epiworld::PostRecoveryFun<tseq> funname = \
4302  [](epiworld::Agent<tseq> * p, \
4303  epiworld::Virus<tseq> & v , \
4304  epiworld::Model<tseq> * m) -> void
4305 
4306 #define EPI_NEW_VIRUSFUN(funname,tseq) inline epiworld_double \
4307  (funname)( \
4308  epiworld::Agent<tseq> * p, \
4309  epiworld::Virus<tseq> & v, \
4310  epiworld::Model<tseq> * m\
4311  )
4312 
4313 #define EPI_NEW_VIRUSFUN_LAMBDA(funname,TSeq) \
4314  epiworld::VirusFun<TSeq> funname = \
4315  [](epiworld::Agent<TSeq> * p, \
4316  epiworld::Virus<TSeq> & v, \
4317  epiworld::Model<TSeq> * m) -> epiworld_double
4318 
4319 #define EPI_RUNIF() m->runif()
4320 
4321 #define EPIWORLD_RUN(a) \
4322  if (a.get_verbose()) \
4323  { \
4324  printf_epiworld("Running the model...\n");\
4325  } \
4326  for (epiworld_fast_uint niter = 0; niter < a.get_ndays(); ++niter)
4327 
4328 #define EPI_TOKENPASTE(a,b) a ## b
4329 #define MPAR(num) *(m->EPI_TOKENPASTE(p,num))
4330 
4331 #define EPI_NEW_UPDATEFUN(funname,tseq) inline void \
4332  (funname)(epiworld::Agent<tseq> * p, epiworld::Model<tseq> * m)
4333 
4334 #define EPI_NEW_UPDATEFUN_LAMBDA(funname,tseq) \
4335  epiworld::UpdateFun<tseq> funname = \
4336  [](epiworld::Agent<tseq> * p, epiworld::Model<tseq> * m) -> void
4337 
4338 #define EPI_NEW_GLOBALFUN(funname,tseq) inline void \
4339  (funname)(epiworld::Model<tseq>* m)
4340 
4341 #define EPI_NEW_GLOBALFUN_LAMBDA(funname,tseq) \
4342  epiworld::GlobalFun<tseq> funname = \
4343  [](epiworld::Model<tseq>* m) -> void
4344 
4345 
4346 #define EPI_NEW_ENTITYTOAGENTFUN(funname,tseq) inline void \
4347  (funname)(epiworld::Entity<tseq> & e, epiworld::Model<tseq> * m)
4348 
4349 #define EPI_NEW_ENTITYTOAGENTFUN_LAMBDA(funname,tseq) \
4350  epiworld::EntityToAgentFun<tseq> funname = \
4351  [](epiworld::Entity<tseq> & e, epiworld::Model<tseq> * m) -> void
4352 
4353 // Use this to make it more efficient for storage if the type is small
4354 // and the pointer is not needed
4355 #define EPI_TYPENAME_TRAITS(tseq, bound) typename std::conditional< \
4356  sizeof( tseq ) <= sizeof( bound ), \
4357  tseq, \
4358  std::shared_ptr< tseq > \
4359  >::type
4360 
4361 #define EPI_IF_TSEQ_LESS_EQ_INT(tseq) \
4362  if constexpr (sizeof( tseq ) <= sizeof( int ))
4363 
4364 #define EPI_CHECK_COALESCE(proposed_, virus_tool_, alt_) \
4365  if (static_cast<int>(proposed_) == -99) {\
4366  if (static_cast<int>(virus_tool_) == -99) \
4367  (proposed_) = (alt_);\
4368  else (proposed_) = (virus_tool_);}
4369 
4370 #endif
4371 /*//////////////////////////////////////////////////////////////////////////////
4373 
4374  End of -include/epiworld/epiworld-macros.hpp-
4375 
4378 
4379 
4380 /*//////////////////////////////////////////////////////////////////////////////
4382 
4383  Start of -include/epiworld/misc.hpp-
4384 
4387 
4388 
4389 #ifndef EPIWORLD_MISC_HPP
4390 #define EPIWORLD_MISC_HPP
4391 
4392 template<typename TSeq>
4393 class Model;
4394 
4395 template<typename TSeq>
4396 class Agent;
4397 
4398 // Relevant for anything using vecHasher function ------------------------------
4403 template <typename T>
4404 struct vecHasher {
4405  std::size_t operator()(std::vector< T > const& dat) const noexcept {
4406 
4407  std::hash< T > hasher;
4408  std::size_t hash = hasher(dat[0u]);
4409 
4410  // ^ makes bitwise XOR
4411  // 0x9e3779b9 is a 32 bit constant (comes from the golden ratio)
4412  // << is a shift operator, something like lhs * 2^(rhs)
4413  if (dat.size() > 1u)
4414  for (epiworld_fast_uint i = 1u; i < dat.size(); ++i)
4415  hash ^= hasher(dat[i]) + 0x9e3779b9 + (hash<<6) + (hash>>2);
4416 
4417  return hash;
4418 
4419  }
4420 };
4421 
4422 template<typename Ta = epiworld_double, typename Tb = epiworld_fast_uint>
4423 using MapVec_type = std::unordered_map< std::vector< Ta >, Tb, vecHasher<Ta>>;
4424 
4437 template<typename TSeq = EPI_DEFAULT_TSEQ>
4438 inline TSeq default_sequence(int seq_count);
4439 
4440 // Making it 'static' so that we don't have problems when including the
4441 // header. This is important during the linkage, e.g., in R.
4442 // See https://en.cppreference.com/w/cpp/language/storage_duration#Linkage
4443 // static int _n_sequences_created = 0;
4444 
4445 template<>
4446 inline bool default_sequence(int seq_count) {
4447 
4448  if (seq_count == 2)
4449  throw std::logic_error("Maximum number of sequence created.");
4450 
4451  return seq_count++ ? false : true;
4452 }
4453 
4454 template<>
4455 inline int default_sequence(int seq_count) {
4456  return seq_count++;
4457 }
4458 
4459 template<>
4460 inline epiworld_double default_sequence(int seq_count) {
4461  return static_cast<epiworld_double>(seq_count++);
4462 }
4463 
4464 template<>
4465 inline std::vector<bool> default_sequence(int seq_count) {
4466 
4467  if (seq_count == 2)
4468  throw std::logic_error("Maximum number of sequence created.");
4469 
4470  return {seq_count++ ? false : true};
4471 }
4472 
4473 template<>
4474 inline std::vector<int> default_sequence(int seq_count) {
4475  return {seq_count++};
4476 }
4477 
4478 template<>
4479 inline std::vector<epiworld_double> default_sequence(int seq_count) {
4480  return {static_cast<epiworld_double>(seq_count++)};
4481 }
4483 
4492 template<typename Ta>
4493 inline bool IN(const Ta & a, const std::vector< Ta > & b) noexcept
4494 {
4495  for (const auto & i : b)
4496  if (a == i)
4497  return true;
4498 
4499  return false;
4500 }
4501 
4515 template<typename TSeq = EPI_DEFAULT_TSEQ, typename TDbl = epiworld_double >
4516 inline int roulette(
4517  const std::vector< TDbl > & probs,
4518  Model<TSeq> * m
4519  )
4520 {
4521 
4522  // Step 1: Computing the prob on none
4523  TDbl p_none = 1.0;
4524  std::vector< int > certain_infection;
4525  certain_infection.reserve(probs.size());
4526 
4527  for (epiworld_fast_uint p = 0u; p < probs.size(); ++p)
4528  {
4529  p_none *= (1.0 - probs[p]);
4530 
4531  if (probs[p] > (1 - 1e-100))
4532  certain_infection.push_back(p);
4533 
4534  }
4535 
4536  TDbl r = static_cast<TDbl>(m->runif());
4537  // If there are one or more probs that go close to 1, sample
4538  // uniformly
4539  if (certain_infection.size() > 0)
4540  return certain_infection[std::floor(r * certain_infection.size())];
4541 
4542  // Step 2: Calculating the prob of none or single
4543  std::vector< TDbl > probs_only_p(probs.size());
4544  TDbl p_none_or_single = p_none;
4545  for (epiworld_fast_uint p = 0u; p < probs.size(); ++p)
4546  {
4547  probs_only_p[p] = probs[p] * (p_none / (1.0 - probs[p]));
4548  p_none_or_single += probs_only_p[p];
4549  }
4550 
4551  // Step 3: Roulette
4552  TDbl cumsum = p_none/p_none_or_single;
4553  if (r < cumsum)
4554  {
4555  return -1;
4556  }
4557 
4558  for (epiworld_fast_uint p = 0u; p < probs.size(); ++p)
4559  {
4560  // If it yield here, then bingo, the individual will acquire the disease
4561  cumsum += probs_only_p[p]/(p_none_or_single);
4562  if (r < cumsum)
4563  return static_cast<int>(p);
4564 
4565  }
4566 
4567 
4568  #ifdef EPI_DEBUG
4569  printf_epiworld("[epi-debug] roulette::cumsum = %.4f\n", cumsum);
4570  #endif
4571 
4572  return static_cast<int>(probs.size() - 1u);
4573 
4574 }
4575 
4576 template<typename TSeq>
4577 inline int roulette(std::vector< double > & probs, Model<TSeq> * m)
4578 {
4579  return roulette<TSeq, double>(probs, m);
4580 }
4581 
4582 template<typename TSeq>
4583 inline int roulette(std::vector< float > & probs, Model<TSeq> * m)
4584 {
4585  return roulette<TSeq, float>(probs, m);
4586 }
4587 
4588 
4589 template<typename TSeq>
4590 inline int roulette(
4591  epiworld_fast_uint nelements,
4592  Model<TSeq> * m
4593  )
4594 {
4595 
4596  if ((nelements * 2) > m->array_double_tmp.size())
4597  {
4598  throw std::logic_error(
4599  "Trying to sample from more data than there is in roulette!" +
4600  std::to_string(nelements) + " vs " +
4601  std::to_string(m->array_double_tmp.size())
4602  );
4603  }
4604 
4605  // Step 1: Computing the prob on none
4606  epiworld_double p_none = 1.0;
4607  epiworld_fast_uint ncertain = 0u;
4608  // std::vector< int > certain_infection;
4609  for (epiworld_fast_uint p = 0u; p < nelements; ++p)
4610  {
4611  p_none *= (1.0 - m->array_double_tmp[p]);
4612 
4613  if (m->array_double_tmp[p] > (1 - 1e-100))
4614  m->array_double_tmp[nelements + ncertain++] = p;
4615  // certain_infection.push_back(p);
4616 
4617  }
4618 
4619  epiworld_double r = m->runif();
4620  // If there are one or more probs that go close to 1, sample
4621  // uniformly
4622  if (ncertain > 0u)
4623  return m->array_double_tmp[nelements + std::floor(ncertain * r)]; // certain_infection[std::floor(r * certain_infection.size())];
4624 
4625  // Step 2: Calculating the prob of none or single
4626  // std::vector< epiworld_double > probs_only_p;
4627  epiworld_double p_none_or_single = p_none;
4628  for (epiworld_fast_uint p = 0u; p < nelements; ++p)
4629  {
4630  m->array_double_tmp[nelements + p] =
4631  m->array_double_tmp[p] * (p_none / (1.0 - m->array_double_tmp[p]));
4632  p_none_or_single += m->array_double_tmp[nelements + p];
4633  }
4634 
4635  // Step 3: Roulette
4636  epiworld_double cumsum = p_none/p_none_or_single;
4637  if (r < cumsum)
4638  return -1;
4639 
4640  for (epiworld_fast_uint p = 0u; p < nelements; ++p)
4641  {
4642  // If it yield here, then bingo, the individual will acquire the disease
4643  cumsum += m->array_double_tmp[nelements + p]/(p_none_or_single);
4644  if (r < cumsum)
4645  return static_cast<int>(p);
4646 
4647  }
4648 
4649  return static_cast<int>(nelements - 1u);
4650 
4651 }
4652 
4669 template <typename T>
4670 inline std::map< std::string, T > read_yaml(std::string fn)
4671 {
4672 
4673  std::ifstream paramsfile(fn);
4674 
4675  if (!paramsfile)
4676  throw std::logic_error("The file " + fn + " was not found.");
4677 
4678  std::regex pattern("^([^:]+)\\s*[:]\\s*([-]?[0-9]+|[-]?[0-9]*\\.[0-9]+)?\\s*$");
4679 
4680  std::string line;
4681  std::smatch match;
4682  auto empty = std::sregex_iterator();
4683 
4684  // Making room
4685  std::map<std::string, T> parameters;
4686 
4687  while (std::getline(paramsfile, line))
4688  {
4689 
4690  // Is it a comment or an empty line?
4691  if (std::regex_match(line, std::regex("^([*].+|//.+|#.+|\\s*)$")))
4692  continue;
4693 
4694  // Finding the pattern, if it doesn't match, then error
4695  std::regex_match(line, match, pattern);
4696 
4697  if (match.empty())
4698  throw std::logic_error("Line has invalid format:\n" + line);
4699 
4700  // Capturing the number
4701  std::string anumber = match[2u].str() + match[3u].str();
4702  T tmp_num = static_cast<T>(
4703  std::strtod(anumber.c_str(), nullptr)
4704  );
4705 
4706  std::string pname = std::regex_replace(
4707  match[1u].str(),
4708  std::regex("^\\s+|\\s+$"),
4709  "");
4710 
4711  // Adding the parameter to the map
4712  parameters[pname] = tmp_num;
4713 
4714  }
4715 
4716  return parameters;
4717 
4718 }
4719 
4720 #endif
4721 /*//////////////////////////////////////////////////////////////////////////////
4723 
4724  End of -include/epiworld/misc.hpp-
4725 
4728 
4729 
4730 /*//////////////////////////////////////////////////////////////////////////////
4732 
4733  Start of -include/epiworld/database-bones.hpp-
4734 
4737 
4738 
4739 #ifndef EPIWORLD_DATABASE_BONES_HPP
4740 #define EPIWORLD_DATABASE_BONES_HPP
4741 
4742 template<typename TSeq>
4743 class Model;
4744 
4745 template<typename TSeq>
4746 class Virus;
4747 
4748 template<typename TSeq>
4749 class UserData;
4750 
4751 template<typename TSeq>
4752 inline void default_add_virus(Event<TSeq> & a, Model<TSeq> * m);
4753 
4754 template<typename TSeq>
4755 inline void default_add_tool(Event<TSeq> & a, Model<TSeq> * m);
4756 
4757 template<typename TSeq>
4758 inline void default_rm_virus(Event<TSeq> & a, Model<TSeq> * m);
4759 
4760 template<typename TSeq>
4761 inline void default_rm_tool(Event<TSeq> & a, Model<TSeq> * m);
4762 
4763 template<typename TSeq>
4764 inline void default_change_state(Event<TSeq> & a, Model<TSeq> * m);
4765 
4771 template<typename TSeq>
4772 class DataBase {
4773  friend class Model<TSeq>;
4774  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
4775  friend void default_add_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
4776  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
4777  friend void default_rm_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
4778  friend void default_change_state<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
4779 private:
4780  Model<TSeq> * model;
4781 
4782  // Variants information
4783  MapVec_type<int,int> virus_id; ///< The squence is the key
4784  std::vector< std::string > virus_name;
4785  std::vector< TSeq> virus_sequence;
4786  std::vector< int > virus_origin_date;
4787  std::vector< int > virus_parent_id;
4788 
4789  MapVec_type<int,int> tool_id; ///< The squence is the key
4790  std::vector< std::string > tool_name;
4791  std::vector< TSeq> tool_sequence;
4792  std::vector< int > tool_origin_date;
4793 
4794  std::function<std::vector<int>(const TSeq&)> seq_hasher = default_seq_hasher<TSeq>;
4795  std::function<std::string(const TSeq &)> seq_writer = default_seq_writer<TSeq>;
4796 
4797  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
4798  std::vector< std::vector<int> > today_virus;
4799 
4800  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
4801  std::vector< std::vector<int> > today_tool;
4802 
4803  // {Susceptible, Infected, etc.}
4804  std::vector< int > today_total;
4805 
4806  // Totals
4807  int today_total_nviruses_active = 0;
4808 
4809  int sampling_freq = 1;
4810 
4811  // Variants history
4812  std::vector< int > hist_virus_date;
4813  std::vector< int > hist_virus_id;
4814  std::vector< epiworld_fast_uint > hist_virus_state;
4815  std::vector< int > hist_virus_counts;
4816 
4817  // Tools history
4818  std::vector< int > hist_tool_date;
4819  std::vector< int > hist_tool_id;
4820  std::vector< epiworld_fast_uint > hist_tool_state;
4821  std::vector< int > hist_tool_counts;
4822 
4823  // Overall hist
4824  std::vector< int > hist_total_date;
4825  std::vector< int > hist_total_nviruses_active;
4826  std::vector< epiworld_fast_uint > hist_total_state;
4827  std::vector< int > hist_total_counts;
4828  std::vector< int > hist_transition_matrix;
4829 
4830  // Transmission network
4831  std::vector< int > transmission_date; ///< Date of the transmission event
4832  std::vector< int > transmission_source; ///< Id of the source
4833  std::vector< int > transmission_target; ///< Id of the target
4834  std::vector< int > transmission_virus; ///< Id of the variant
4835  std::vector< int > transmission_source_exposure_date; ///< Date when the source acquired the variant
4836 
4837  std::vector< int > transition_matrix;
4838 
4839  UserData<TSeq> user_data;
4840 
4841  void update_state(
4842  epiworld_fast_uint prev_state,
4843  epiworld_fast_uint new_state,
4844  bool undo = false
4845  );
4846 
4847  void update_virus(
4848  epiworld_fast_uint virus_id,
4849  epiworld_fast_uint prev_state,
4850  epiworld_fast_uint new_state
4851  );
4852 
4853  void update_tool(
4854  epiworld_fast_uint tool_id,
4855  epiworld_fast_uint prev_state,
4856  epiworld_fast_uint new_state
4857  );
4858 
4859  void record_transition(epiworld_fast_uint from, epiworld_fast_uint to, bool undo);
4860 
4861 
4862 public:
4863 
4864  #ifdef EPI_DEBUG
4865  int n_transmissions_potential = 0;
4866  int n_transmissions_today = 0;
4867  #endif
4868 
4869  DataBase() = delete;
4870  DataBase(Model<TSeq> & m) : model(&m), user_data(m) {};
4871  DataBase(const DataBase<TSeq> & db);
4872  // DataBase<TSeq> & operator=(const DataBase<TSeq> & m);
4873 
4882  void record_virus(Virus<TSeq> & v);
4883  void record_tool(Tool<TSeq> & t);
4884  void set_seq_hasher(std::function<std::vector<int>(TSeq)> fun);
4885  void reset();
4886  Model<TSeq> * get_model();
4887  void record();
4888 
4889  const std::vector< TSeq > & get_sequence() const;
4890  const std::vector< int > & get_nexposed() const;
4891  size_t size() const;
4892 
4906  int get_today_total(const std::string & what) const;
4907  int get_today_total(const epiworld_fast_uint & what) const;
4908  void get_today_total(
4909  std::vector< std::string > * state = nullptr,
4910  std::vector< int > * counts = nullptr
4911  ) const;
4912 
4913  void get_today_virus(
4914  std::vector< std::string > & state,
4915  std::vector< int > & id,
4916  std::vector< int > & counts
4917  ) const;
4918 
4919  void get_today_transition_matrix(
4920  std::vector< int > & counts
4921  ) const;
4922 
4923  void get_hist_total(
4924  std::vector< int > * date,
4925  std::vector< std::string > * state,
4926  std::vector< int > * counts
4927  ) const;
4928 
4929  void get_hist_virus(
4930  std::vector< int > & date,
4931  std::vector< int > & id,
4932  std::vector< std::string > & state,
4933  std::vector< int > & counts
4934  ) const;
4935 
4936  void get_hist_tool(
4937  std::vector< int > & date,
4938  std::vector< int > & id,
4939  std::vector< std::string > & state,
4940  std::vector< int > & counts
4941  ) const;
4942 
4943  void get_hist_transition_matrix(
4944  std::vector< std::string > & state_from,
4945  std::vector< std::string > & state_to,
4946  std::vector< int > & date,
4947  std::vector< int > & counts,
4948  bool skip_zeros
4949  ) const;
4951 
4962  void get_transmissions(
4963  std::vector<int> & date,
4964  std::vector<int> & source,
4965  std::vector<int> & target,
4966  std::vector<int> & virus,
4967  std::vector<int> & source_exposure_date
4968  ) const;
4969 
4970  void get_transmissions(
4971  int * date,
4972  int * source,
4973  int * target,
4974  int * virus,
4975  int * source_exposure_date
4976  ) const;
4978 
4979  void write_data(
4980  std::string fn_virus_info,
4981  std::string fn_virus_hist,
4982  std::string fn_tool_info,
4983  std::string fn_tool_hist,
4984  std::string fn_total_hist,
4985  std::string fn_transmission,
4986  std::string fn_transition,
4987  std::string fn_reproductive_number,
4988  std::string fn_generation_time
4989  ) const;
4990 
4991  /***
4992  * @brief Record a transmission event
4993  * @param i,j Integers. Id of the source and target agents.
4994  * @param virus Integer. Id of the virus.
4995  * @param i_expo_date Integer. Date when the source agent was infected.
4996  * @details
4997  * If i is -1, then it means that the agent was assigned a virus at the
4998  * beginning of the simulation.
4999  */
5000  void record_transmission(int i, int j, int virus, int i_expo_date);
5001 
5002  size_t get_n_viruses() const;
5003  size_t get_n_tools() const;
5004 
5005  void set_user_data(std::vector< std::string > names);
5006  void add_user_data(std::vector< epiworld_double > x);
5007  void add_user_data(epiworld_fast_uint j, epiworld_double x);
5008  UserData<TSeq> & get_user_data();
5009 
5010 
5026  MapVec_type<int,int> get_reproductive_number() const;
5027 
5028  void get_reproductive_number(
5029  std::string fn
5030  ) const;
5032 
5046  std::vector< epiworld_double > get_transition_probability(
5047  bool print = true,
5048  bool normalize = true
5049  ) const;
5050 
5051  bool operator==(const DataBase<TSeq> & other) const;
5052  bool operator!=(const DataBase<TSeq> & other) const {return !operator==(other);};
5053 
5063  void get_generation_time(
5064  std::vector< int > & agent_id,
5065  std::vector< int > & virus_id,
5066  std::vector< int > & time,
5067  std::vector< int > & gentime
5068  ) const;
5069 
5070  void get_generation_time(
5071  std::string fn
5072  ) const;
5074 
5075 };
5076 
5077 
5078 #endif
5079 /*//////////////////////////////////////////////////////////////////////////////
5081 
5082  End of -include/epiworld/database-bones.hpp-
5083 
5086 
5087 
5088 
5089 template<typename TSeq>
5090 inline void DataBase<TSeq>::reset()
5091 {
5092 
5093  // Initializing the counts
5094  today_total.resize(model->nstates);
5095  std::fill(today_total.begin(), today_total.end(), 0);
5096  for (auto & p : model->get_agents())
5097  ++today_total[p.get_state()];
5098 
5099  #ifdef EPI_DEBUG
5100  // Only the first should be different from zero
5101  {
5102  int n = static_cast<int>(model->size());
5103  if (today_total[0] != n)
5104  throw std::runtime_error("The number of susceptible agents is not equal to the total number of agents.");
5105 
5106  if (std::accumulate(today_total.begin(), today_total.end(), 0) != n)
5107  throw std::runtime_error("The total number of agents is not equal to the sum of the number of agents in each state.");
5108 
5109  }
5110  #endif
5111 
5112 
5113  transition_matrix.resize(model->nstates * model->nstates);
5114  std::fill(transition_matrix.begin(), transition_matrix.end(), 0);
5115  for (size_t s = 0u; s < model->nstates; ++s)
5116  transition_matrix[s + s * model->nstates] = today_total[s];
5117 
5118  hist_virus_date.clear();
5119  hist_virus_id.clear();
5120  hist_virus_state.clear();
5121  hist_virus_counts.clear();
5122 
5123  hist_tool_date.clear();
5124  hist_tool_id.clear();
5125  hist_tool_state.clear();
5126  hist_tool_counts.clear();
5127 
5128  today_virus.resize(get_n_viruses());
5129  for (auto& virus_states : today_virus)
5130  virus_states.assign(model->nstates, 0);
5131 
5132  today_tool.resize(get_n_tools());
5133  for (auto& tool_states : today_tool)
5134  tool_states.assign(model->nstates, 0);
5135 
5136  hist_total_date.clear();
5137  hist_total_state.clear();
5138  hist_total_nviruses_active.clear();
5139  hist_total_counts.clear();
5140  hist_transition_matrix.clear();
5141 
5142  transmission_date.clear();
5143  transmission_virus.clear();
5144  transmission_source.clear();
5145  transmission_target.clear();
5146  transmission_source_exposure_date.clear();
5147 
5148  return;
5149 
5150 }
5151 
5152 template<typename TSeq>
5153 inline DataBase<TSeq>::DataBase(const DataBase<TSeq> & db) :
5154  virus_id(db.virus_id),
5155  virus_name(db.virus_name),
5156  virus_sequence(db.virus_sequence),
5157  virus_origin_date(db.virus_origin_date),
5158  virus_parent_id(db.virus_parent_id),
5159  tool_id(db.tool_id),
5160  tool_name(db.tool_name),
5161  tool_sequence(db.tool_sequence),
5162  tool_origin_date(db.tool_origin_date),
5163  seq_hasher(db.seq_hasher),
5164  seq_writer(db.seq_writer),
5165  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
5166  today_virus(db.today_virus),
5167  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
5168  today_tool(db.today_tool),
5169  // {Susceptible, Infected, etc.}
5170  today_total(db.today_total),
5171  // Totals
5172  today_total_nviruses_active(db.today_total_nviruses_active),
5173  sampling_freq(db.sampling_freq),
5174  // Variants history
5175  hist_virus_date(db.hist_virus_date),
5176  hist_virus_id(db.hist_virus_id),
5177  hist_virus_state(db.hist_virus_state),
5178  hist_virus_counts(db.hist_virus_counts),
5179  // Tools history
5180  hist_tool_date(db.hist_tool_date),
5181  hist_tool_id(db.hist_tool_id),
5182  hist_tool_state(db.hist_tool_state),
5183  hist_tool_counts(db.hist_tool_counts),
5184  // Overall hist
5185  hist_total_date(db.hist_total_date),
5186  hist_total_nviruses_active(db.hist_total_nviruses_active),
5187  hist_total_state(db.hist_total_state),
5188  hist_total_counts(db.hist_total_counts),
5189  hist_transition_matrix(db.hist_transition_matrix),
5190  // Transmission network
5191  transmission_date(db.transmission_date),
5192  transmission_source(db.transmission_source),
5193  transmission_target(db.transmission_target),
5194  transmission_virus(db.transmission_virus),
5195  transmission_source_exposure_date(db.transmission_source_exposure_date),
5196  transition_matrix(db.transition_matrix),
5197  user_data(nullptr)
5198 {}
5199 
5200 // DataBase<TSeq> & DataBase<TSeq>::operator=(const DataBase<TSeq> & m)
5201 // {
5202 
5203 // }
5204 
5205 template<typename TSeq>
5206 inline Model<TSeq> * DataBase<TSeq>::get_model() {
5207  return model;
5208 }
5209 
5210 template<typename TSeq>
5211 inline const std::vector< TSeq > & DataBase<TSeq>::get_sequence() const {
5212  return virus_sequence;
5213 }
5214 
5215 template<typename TSeq>
5216 inline void DataBase<TSeq>::record()
5217 {
5218 
5220  // DEBUGGING BLOCK
5222  EPI_DEBUG_SUM_INT(today_total, model->size())
5223  EPI_DEBUG_ALL_NON_NEGATIVE(today_total)
5224 
5225  #ifdef EPI_DEBUG
5226  // Checking whether the sums correspond
5227  std::vector< int > _today_total_cp(today_total.size(), 0);
5228  for (auto & p : model->population)
5229  _today_total_cp[p.get_state()]++;
5230 
5231  EPI_DEBUG_VECTOR_MATCH_INT(
5232  _today_total_cp, today_total,
5233  "Sums of __today_total_cp in database-meat.hpp"
5234  )
5235 
5236  if (model->today() == 0)
5237  {
5238  if (hist_total_date.size() != 0)
5239  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_total_date should be of length 0.")
5240  if (hist_total_nviruses_active.size() != 0)
5241  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_total_nviruses_active should be of length 0.")
5242  if (hist_total_state.size() != 0)
5243  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_total_state should be of length 0.")
5244  if (hist_total_counts.size() != 0)
5245  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_total_counts should be of length 0.")
5246  if (hist_virus_date.size() != 0)
5247  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_virus_date should be of length 0.")
5248  if (hist_virus_id.size() != 0)
5249  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_virus_id should be of length 0.")
5250  if (hist_virus_state.size() != 0)
5251  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_virus_state should be of length 0.")
5252  if (hist_virus_counts.size() != 0)
5253  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_virus_counts should be of length 0.")
5254  if (hist_tool_date.size() != 0)
5255  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_tool_date should be of length 0.")
5256  if (hist_tool_id.size() != 0)
5257  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_tool_id should be of length 0.")
5258  if (hist_tool_state.size() != 0)
5259  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_tool_state should be of length 0.")
5260  if (hist_tool_counts.size() != 0)
5261  EPI_DEBUG_ERROR(std::logic_error, "DataBase::record hist_tool_counts should be of length 0.")
5262  }
5263  #endif
5265 
5266  // Only store every now and then
5267  if ((model->today() % sampling_freq) == 0)
5268  {
5269 
5270  // Recording virus's history
5271  for (auto & p : virus_id)
5272  {
5273 
5274  for (epiworld_fast_uint s = 0u; s < model->nstates; ++s)
5275  {
5276 
5277  hist_virus_date.push_back(model->today());
5278  hist_virus_id.push_back(p.second);
5279  hist_virus_state.push_back(s);
5280  hist_virus_counts.push_back(today_virus[p.second][s]);
5281 
5282  }
5283 
5284  }
5285 
5286  // Recording tool's history
5287  for (auto & p : tool_id)
5288  {
5289 
5290  for (epiworld_fast_uint s = 0u; s < model->nstates; ++s)
5291  {
5292 
5293  hist_tool_date.push_back(model->today());
5294  hist_tool_id.push_back(p.second);
5295  hist_tool_state.push_back(s);
5296  hist_tool_counts.push_back(today_tool[p.second][s]);
5297 
5298  }
5299 
5300  }
5301 
5302  // Recording the overall history
5303  for (epiworld_fast_uint s = 0u; s < model->nstates; ++s)
5304  {
5305  hist_total_date.push_back(model->today());
5306  hist_total_nviruses_active.push_back(today_total_nviruses_active);
5307  hist_total_state.push_back(s);
5308  hist_total_counts.push_back(today_total[s]);
5309  }
5310 
5311  for (const auto& cell : transition_matrix)
5312  hist_transition_matrix.push_back(cell);
5313 
5314  // Now the diagonal must reflect the state
5315  for (size_t s_i = 0u; s_i < model->nstates; ++s_i)
5316  {
5317 
5318  for (size_t s_j = 0u; s_j < model->nstates; ++s_j)
5319  {
5320 
5321  if ((s_i != s_j) && (transition_matrix[s_i + s_j * model->nstates] > 0))
5322  {
5323  transition_matrix[s_j + s_j * model->nstates] +=
5324  transition_matrix[s_i + s_j * model->nstates];
5325 
5326  transition_matrix[s_i + s_j * model->nstates] = 0;
5327  }
5328 
5329  }
5330 
5331  }
5332 
5333  #ifdef EPI_DEBUG
5334  for (size_t s_i = 0u; s_i < model->nstates; ++s_i)
5335  {
5336  if (transition_matrix[s_i + s_i * model->nstates] !=
5337  today_total[s_i])
5338  throw std::logic_error(
5339  "The diagonal of the updated transition Matrix should match the daily totals"
5340  );
5341  }
5342  #endif
5343 
5344  }
5345 
5346 }
5347 
5348 template<typename TSeq>
5349 inline void DataBase<TSeq>::record_virus(Virus<TSeq> & v)
5350 {
5351 
5352  // If no sequence, then need to add one. This is regardless of the case
5353  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5354  {
5355  if (v.get_sequence() == -1)
5356  v.set_sequence(default_sequence<TSeq>(
5357  static_cast<int>(virus_name.size())
5358  ));
5359  }
5360  else
5361  {
5362  if (v.get_sequence() == nullptr)
5363  v.set_sequence(default_sequence<TSeq>(
5364  static_cast<int>(virus_name.size())
5365  ));
5366  }
5367 
5368  // Negative id -> virus hasn't been recorded
5369  if (v.get_id() < 0)
5370  {
5371 
5372  epiworld_fast_uint new_id = virus_id.size();
5373  virus_name.push_back(v.get_name());
5374 
5375  // Generating the hash
5376  std::vector< int > hash;
5377  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5378  {
5379  hash = seq_hasher(v.get_sequence());
5380  virus_id[hash] = new_id;
5381  virus_sequence.push_back(v.get_sequence());
5382  }
5383  else
5384  {
5385  hash = seq_hasher(*v.get_sequence());
5386  virus_id[hash] = new_id;
5387  virus_sequence.push_back(*v.get_sequence());
5388  }
5389 
5390 
5391  virus_origin_date.push_back(model->today());
5392 
5393  virus_parent_id.push_back(v.get_id()); // Must be -99
5394 
5395  today_virus.push_back({});
5396  today_virus[new_id].resize(model->nstates, 0);
5397 
5398  // Updating the variant
5399  v.set_id(new_id);
5400  v.set_date(model->today());
5401 
5402  today_total_nviruses_active++;
5403 
5404  }
5405  else
5406  { // In this case, the virus is already on record, need to make sure
5407  // The new sequence is new.
5408 
5409  // Updating registry
5410  std::vector< int > hash;
5411  EPI_IF_TSEQ_LESS_EQ_INT(TSeq)
5412  {
5413  hash = seq_hasher(v.get_sequence());
5414  }
5415  else
5416  {
5417  hash = seq_hasher(*v.get_sequence());
5418  }
5419  epiworld_fast_uint old_id = v.get_id();
5420  epiworld_fast_uint new_id;
5421 
5422  // If the sequence is new, then it means that the
5423  if (virus_id.find(hash) == virus_id.end())
5424  {
5425 
5426  new_id = virus_id.size();
5427  virus_id[hash] = new_id;
5428  virus_name.push_back(v.get_name());
5429 
5430  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5431  {
5432  virus_sequence.push_back(v.get_sequence());
5433  }
5434  else
5435  {
5436  virus_sequence.push_back(*v.get_sequence());
5437  }
5438 
5439  virus_origin_date.push_back(model->today());
5440 
5441  virus_parent_id.push_back(old_id);
5442 
5443  today_virus.push_back({});
5444  today_virus[new_id].resize(model->nstates, 0);
5445 
5446  // Updating the variant
5447  v.set_id(new_id);
5448  v.set_date(model->today());
5449 
5450  today_total_nviruses_active++;
5451 
5452  } else {
5453 
5454  // Finding the id
5455  new_id = virus_id[hash];
5456 
5457  // Reflecting the change
5458  v.set_id(new_id);
5459  v.set_date(virus_origin_date[new_id]);
5460 
5461  }
5462 
5463  // Moving statistics (only if we are affecting an individual)
5464  if (v.get_agent() != nullptr)
5465  {
5466  // Correcting math
5467  epiworld_fast_uint tmp_state = v.get_agent()->get_state();
5468  today_virus[old_id][tmp_state]--;
5469  today_virus[new_id][tmp_state]++;
5470 
5471  }
5472 
5473  }
5474 
5475  return;
5476 
5477 }
5478 
5479 template<typename TSeq>
5480 inline void DataBase<TSeq>::record_tool(Tool<TSeq> & t)
5481 {
5482 
5483  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5484  {
5485  if (t.get_sequence() == -1)
5486  t.set_sequence(default_sequence<TSeq>(
5487  static_cast<int>(tool_name.size())
5488  ));
5489  }
5490  else
5491  {
5492  if (t.get_sequence() == nullptr)
5493  t.set_sequence(default_sequence<TSeq>(
5494  static_cast<int>(tool_name.size())
5495  ));
5496  }
5497 
5498  if (t.get_id() < 0)
5499  {
5500 
5501  epiworld_fast_uint new_id = tool_id.size();
5502  tool_name.push_back(t.get_name());
5503 
5504  std::vector< int > hash;
5505  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5506  {
5507  hash = seq_hasher(t.get_sequence());
5508  tool_id[hash] = new_id;
5509  tool_sequence.push_back(t.get_sequence());
5510  }
5511  else
5512  {
5513  hash = seq_hasher(*t.get_sequence());
5514  tool_id[hash] = new_id;
5515  tool_sequence.push_back(*t.get_sequence());
5516 
5517  }
5518  tool_origin_date.push_back(model->today());
5519 
5520  today_tool.push_back({});
5521  today_tool[new_id].resize(model->nstates, 0);
5522 
5523  // Updating the tool
5524  t.set_id(new_id);
5525  t.set_date(model->today());
5526 
5527  } else {
5528 
5529  // Updating registry
5530  std::vector< int > hash;
5531  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5532  {
5533  hash = seq_hasher(t.get_sequence());
5534  }
5535  else
5536  {
5537  hash = seq_hasher(*t.get_sequence());
5538  }
5539  epiworld_fast_uint old_id = t.get_id();
5540  epiworld_fast_uint new_id;
5541 
5542  if (tool_id.find(hash) == tool_id.end())
5543  {
5544 
5545  new_id = tool_id.size();
5546  tool_id[hash] = new_id;
5547  tool_name.push_back(t.get_name());
5548 
5549  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
5550  {
5551  tool_sequence.push_back(t.get_sequence());
5552  }
5553  else
5554  {
5555  tool_sequence.push_back(*t.get_sequence());
5556  }
5557 
5558  tool_origin_date.push_back(model->today());
5559 
5560  today_tool.push_back({});
5561  today_tool[new_id].resize(model->nstates, 0);
5562 
5563  // Updating the tool
5564  t.set_id(new_id);
5565  t.set_date(model->today());
5566 
5567  } else {
5568 
5569  // Finding the id
5570  new_id = tool_id[hash];
5571 
5572  // Reflecting the change
5573  t.set_id(new_id);
5574  t.set_date(tool_origin_date[new_id]);
5575 
5576  }
5577 
5578  // Moving statistics (only if we are affecting an individual)
5579  if (t.get_agent() != nullptr)
5580  {
5581  // Correcting math
5582  epiworld_fast_uint tmp_state = t.get_agent()->get_state();
5583  today_tool[old_id][tmp_state]--;
5584  today_tool[new_id][tmp_state]++;
5585 
5586  }
5587 
5588  }
5589 
5590 
5591 
5592  return;
5593 }
5594 
5595 template<typename TSeq>
5596 inline size_t DataBase<TSeq>::size() const
5597 {
5598  return virus_id.size();
5599 }
5600 
5601 template<typename TSeq>
5602 inline void DataBase<TSeq>::update_state(
5603  epiworld_fast_uint prev_state,
5604  epiworld_fast_uint new_state,
5605  bool undo
5606 ) {
5607 
5608  if (prev_state == new_state)
5609  return; // No need to update if the state is the same
5610 
5611  #ifdef EPI_DEBUG
5612  // Checking ranges (should be within expected)
5613  if ((prev_state >= model->nstates))
5614  throw std::out_of_range(
5615  "prev_state is out of range in DataBase::update_state"
5616  );
5617  if ((new_state >= model->nstates))
5618  throw std::out_of_range(
5619  "new_state is out of range in DataBase::update_state"
5620  );
5621  if (prev_state == new_state)
5622  throw std::logic_error(
5623  "prev_state and new_state are the same in DataBase::update_state"
5624  );
5625  #endif
5626 
5627  if (undo)
5628  {
5629 
5630  today_total[prev_state]++;
5631  today_total[new_state]--;
5632 
5633  } else {
5634 
5635  today_total[prev_state]--;
5636  today_total[new_state]++;
5637 
5638  }
5639 
5640  record_transition(prev_state, new_state, undo);
5641 
5642  return;
5643 }
5644 
5645 template<typename TSeq>
5646 inline void DataBase<TSeq>::update_virus(
5647  epiworld_fast_uint virus_id,
5648  epiworld_fast_uint prev_state,
5649  epiworld_fast_uint new_state
5650 ) {
5651 
5652  today_virus[virus_id][prev_state]--;
5653  today_virus[virus_id][new_state]++;
5654 
5655  return;
5656 
5657 }
5658 
5659 template<typename TSeq>
5660 inline void DataBase<TSeq>::update_tool(
5661  epiworld_fast_uint tool_id,
5662  epiworld_fast_uint prev_state,
5663  epiworld_fast_uint new_state
5664 ) {
5665 
5666 
5667  today_tool[tool_id][prev_state]--;
5668  today_tool[tool_id][new_state]++;
5669 
5670  return;
5671 
5672 }
5673 
5674 template<typename TSeq>
5675 inline void DataBase<TSeq>::record_transition(
5676  epiworld_fast_uint from,
5677  epiworld_fast_uint to,
5678  bool undo
5679 ) {
5680 
5681  if (undo)
5682  {
5683 
5684  transition_matrix[to * model->nstates + from]--;
5685  transition_matrix[from * model->nstates + from]++;
5686 
5687  } else {
5688 
5689  transition_matrix[to * model->nstates + from]++;
5690  transition_matrix[from * model->nstates + from]--;
5691 
5692  }
5693 
5694  #ifdef EPI_DEBUG
5695  if (transition_matrix[from * model->nstates + from] < 0)
5696  throw std::logic_error("An entry in transition matrix is negative.");
5697  #endif
5698 
5699 }
5700 
5701 template<typename TSeq>
5702 inline int DataBase<TSeq>::get_today_total(
5703  const std::string & what
5704 ) const
5705 {
5706 
5707  for (auto i = 0u; i < model->states_labels.size(); ++i)
5708  {
5709  if (model->states_labels[i] == what)
5710  return today_total[i];
5711  }
5712 
5713  throw std::range_error("The value '" + what + "' is not in the model.");
5714 
5715 }
5716 
5717 template<typename TSeq>
5718 inline void DataBase<TSeq>::get_today_total(
5719  std::vector< std::string > * state,
5720  std::vector< int > * counts
5721 ) const
5722 {
5723  if (state != nullptr)
5724  (*state) = model->states_labels;
5725 
5726  if (counts != nullptr)
5727  *counts = today_total;
5728 
5729 }
5730 
5731 template<typename TSeq>
5732 inline void DataBase<TSeq>::get_today_virus(
5733  std::vector< std::string > & state,
5734  std::vector< int > & id,
5735  std::vector< int > & counts
5736  ) const
5737 {
5738 
5739  state.resize(today_virus.size(), "");
5740  id.resize(today_virus.size(), 0);
5741  counts.resize(today_virus.size(),0);
5742 
5743  int n = 0u;
5744  for (epiworld_fast_uint v = 0u; v < today_virus.size(); ++v)
5745  for (epiworld_fast_uint s = 0u; s < model->states_labels.size(); ++s)
5746  {
5747  state[n] = model->states_labels[s];
5748  id[n] = static_cast<int>(v);
5749  counts[n++] = today_virus[v][s];
5750 
5751  }
5752 
5753 }
5754 
5755 template<typename TSeq>
5756 inline void DataBase<TSeq>::get_hist_total(
5757  std::vector< int > * date,
5758  std::vector< std::string > * state,
5759  std::vector< int > * counts
5760 ) const
5761 {
5762 
5763  if (date != nullptr)
5764  *date = hist_total_date;
5765 
5766  if (state != nullptr)
5767  {
5768  state->resize(hist_total_state.size(), "");
5769  for (epiworld_fast_uint i = 0u; i < hist_total_state.size(); ++i)
5770  state->operator[](i) = model->states_labels[hist_total_state[i]];
5771  }
5772 
5773  if (counts != nullptr)
5774  *counts = hist_total_counts;
5775 
5776  return;
5777 
5778 }
5779 
5780 template<typename TSeq>
5781 inline void DataBase<TSeq>::get_hist_virus(
5782  std::vector< int > & date,
5783  std::vector< int > & id,
5784  std::vector< std::string > & state,
5785  std::vector< int > & counts
5786 ) const {
5787 
5788  date = hist_virus_date;
5789  const auto& labels = model->states_labels;
5790 
5791  id = hist_virus_id;
5792  state.resize(hist_virus_state.size(), "");
5793  for (epiworld_fast_uint i = 0u; i < hist_virus_state.size(); ++i)
5794  state[i] = labels[hist_virus_state[i]];
5795 
5796  counts = hist_virus_counts;
5797 
5798  return;
5799 
5800 }
5801 
5802 
5803 template<typename TSeq>
5804 inline void DataBase<TSeq>::get_hist_tool(
5805  std::vector< int > & date,
5806  std::vector< int > & id,
5807  std::vector< std::string > & state,
5808  std::vector< int > & counts
5809 ) const {
5810 
5811  date = hist_tool_date;
5812  const auto& labels = model->states_labels;
5813 
5814  id = hist_tool_id;
5815  state.resize(hist_tool_state.size(), "");
5816  for (size_t i = 0u; i < hist_tool_state.size(); ++i)
5817  state[i] = labels[hist_tool_state[i]];
5818 
5819  counts = hist_tool_counts;
5820 
5821  return;
5822 
5823 }
5824 
5825 template<typename TSeq>
5826 inline void DataBase<TSeq>::get_today_transition_matrix(
5827  std::vector< int > & counts
5828 ) const
5829 {
5830 
5831  counts = transition_matrix;
5832 
5833  return;
5834 
5835 }
5836 
5837 template<typename TSeq>
5838 inline void DataBase<TSeq>::get_hist_transition_matrix(
5839  std::vector< std::string > & state_from,
5840  std::vector< std::string > & state_to,
5841  std::vector< int > & date,
5842  std::vector< int > & counts,
5843  bool skip_zeros
5844 ) const
5845 {
5846 
5847  size_t n = this->hist_transition_matrix.size();
5848 
5849  // Clearing the previous vectors
5850  state_from.clear();
5851  state_to.clear();
5852  date.clear();
5853  counts.clear();
5854 
5855  // Reserving space
5856  state_from.reserve(n);
5857  state_to.reserve(n);
5858  date.reserve(n);
5859  counts.reserve(n);
5860 
5861  size_t n_states = model->nstates;
5862  size_t n_steps = model->get_ndays();
5863 
5864  // If n is zero, then we are done
5865  if (n == 0u)
5866  return;
5867 
5868  for (size_t step = 0u; step <= n_steps; ++step) // The final step counts
5869  {
5870  for (size_t j = 0u; j < n_states; ++j) // Column major storage
5871  {
5872  for (size_t i = 0u; i < n_states; ++i)
5873  {
5874  // Retrieving the value of the day
5875  int v = hist_transition_matrix[
5876  step * n_states * n_states + // Day of the data
5877  j * n_states + // Column (to)
5878  i // Row (from)
5879  ];
5880 
5881  // If we are skipping the zeros and it is zero, then don't save
5882  if (skip_zeros && v == 0)
5883  continue;
5884 
5885  state_from.push_back(model->states_labels[i]);
5886  state_to.push_back(model->states_labels[j]);
5887  date.push_back(hist_total_date[step * n_states]);
5888  counts.push_back(v);
5889 
5890  }
5891 
5892  }
5893  }
5894 
5895  return;
5896 
5897 
5898 }
5899 
5900 template<typename TSeq>
5901 inline void DataBase<TSeq>::get_transmissions(
5902  std::vector<int> & date,
5903  std::vector<int> & source,
5904  std::vector<int> & target,
5905  std::vector<int> & virus,
5906  std::vector<int> & source_exposure_date
5907 ) const
5908 {
5909 
5910  size_t nevents = transmission_date.size();
5911 
5912  date.resize(nevents);
5913  source.resize(nevents);
5914  target.resize(nevents);
5915  virus.resize(nevents);
5916  source_exposure_date.resize(nevents);
5917 
5918  get_transmissions(
5919  &date[0u],
5920  &source[0u],
5921  &target[0u],
5922  &virus[0u],
5923  &source_exposure_date[0u]
5924  );
5925 
5926 }
5927 
5928 template<typename TSeq>
5929 inline void DataBase<TSeq>::get_transmissions(
5930  int * date,
5931  int * source,
5932  int * target,
5933  int * virus,
5934  int * source_exposure_date
5935 ) const
5936 {
5937 
5938  size_t nevents = transmission_date.size();
5939 
5940  for (size_t i = 0u; i < nevents; ++i)
5941  {
5942 
5943  *(date + i) = transmission_date.at(i);
5944  *(source + i) = transmission_source.at(i);
5945  *(target + i) = transmission_target.at(i);
5946  *(virus + i) = transmission_virus.at(i);
5947  *(source_exposure_date + i) = transmission_source_exposure_date.at(i);
5948 
5949  }
5950 
5951 }
5952 
5953 template<typename TSeq>
5954 inline void DataBase<TSeq>::write_data(
5955  std::string fn_virus_info,
5956  std::string fn_virus_hist,
5957  std::string fn_tool_info,
5958  std::string fn_tool_hist,
5959  std::string fn_total_hist,
5960  std::string fn_transmission,
5961  std::string fn_transition,
5962  std::string fn_reproductive_number,
5963  std::string fn_generation_time
5964 ) const
5965 {
5966 
5967  if (fn_virus_info != "")
5968  {
5969  std::ofstream file_virus_info(fn_virus_info, std::ios_base::out);
5970 
5971  // Check if the file exists and throw an error if it doesn't
5972  if (!file_virus_info)
5973  {
5974  throw std::runtime_error(
5975  "Could not open file \"" + fn_virus_info +
5976  "\" for writing.")
5977  ;
5978  }
5979 
5980 
5981  file_virus_info <<
5982  #ifdef EPI_DEBUG
5983  "thread" << "virus_id " << "virus " << "virus_sequence " << "date_recorded " << "parent\n";
5984  #else
5985  "virus_id " << "virus " << "virus_sequence " << "date_recorded " << "parent\n";
5986  #endif
5987 
5988  for (const auto & v : virus_id)
5989  {
5990  int id = v.second;
5991  file_virus_info <<
5992  #ifdef EPI_DEBUG
5993  EPI_GET_THREAD_ID() << " " <<
5994  #endif
5995  id << " \"" <<
5996  virus_name[id] << "\" " <<
5997  seq_writer(virus_sequence[id]) << " " <<
5998  virus_origin_date[id] << " " <<
5999  virus_parent_id[id] << "\n";
6000  }
6001 
6002  }
6003 
6004  if (fn_virus_hist != "")
6005  {
6006  std::ofstream file_virus(fn_virus_hist, std::ios_base::out);
6007 
6008  // Repeat the same error if the file doesn't exists
6009  if (!file_virus)
6010  {
6011  throw std::runtime_error(
6012  "Could not open file \"" + fn_virus_hist +
6013  "\" for writing.")
6014  ;
6015  }
6016 
6017  file_virus <<
6018  #ifdef EPI_DEBUG
6019  "thread "<< "date " << "virus_id " << "virus " << "state " << "n\n";
6020  #else
6021  "date " << "virus_id " << "virus " << "state " << "n\n";
6022  #endif
6023 
6024  for (epiworld_fast_uint i = 0; i < hist_virus_id.size(); ++i)
6025  file_virus <<
6026  #ifdef EPI_DEBUG
6027  EPI_GET_THREAD_ID() << " " <<
6028  #endif
6029  hist_virus_date[i] << " " <<
6030  hist_virus_id[i] << " \"" <<
6031  virus_name[hist_virus_id[i]] << "\" " <<
6032  model->states_labels[hist_virus_state[i]] << " " <<
6033  hist_virus_counts[i] << "\n";
6034  }
6035 
6036  if (fn_tool_info != "")
6037  {
6038  std::ofstream file_tool_info(fn_tool_info, std::ios_base::out);
6039 
6040  // Repeat the same error if the file doesn't exists
6041  if (!file_tool_info)
6042  {
6043  throw std::runtime_error(
6044  "Could not open file \"" + fn_tool_info +
6045  "\" for writing.")
6046  ;
6047  }
6048 
6049  file_tool_info <<
6050  #ifdef EPI_DEBUG
6051  "thread " <<
6052  #endif
6053  "id " << "tool_name " << "tool_sequence " << "date_recorded\n";
6054 
6055  for (const auto & t : tool_id)
6056  {
6057  int id = t.second;
6058  file_tool_info <<
6059  #ifdef EPI_DEBUG
6060  EPI_GET_THREAD_ID() << " " <<
6061  #endif
6062  id << " \"" <<
6063  tool_name[id] << "\" " <<
6064  seq_writer(tool_sequence[id]) << " " <<
6065  tool_origin_date[id] << "\n";
6066  }
6067 
6068  }
6069 
6070  if (fn_tool_hist != "")
6071  {
6072  std::ofstream file_tool_hist(fn_tool_hist, std::ios_base::out);
6073 
6074  // Repeat the same error if the file doesn't exists
6075  if (!file_tool_hist)
6076  {
6077  throw std::runtime_error(
6078  "Could not open file \"" + fn_tool_hist +
6079  "\" for writing.")
6080  ;
6081  }
6082 
6083  file_tool_hist <<
6084  #ifdef EPI_DEBUG
6085  "thread " <<
6086  #endif
6087  "date " << "id " << "state " << "n\n";
6088 
6089  for (epiworld_fast_uint i = 0; i < hist_tool_id.size(); ++i)
6090  file_tool_hist <<
6091  #ifdef EPI_DEBUG
6092  EPI_GET_THREAD_ID() << " " <<
6093  #endif
6094  hist_tool_date[i] << " " <<
6095  hist_tool_id[i] << " \"" <<
6096  model->states_labels[hist_tool_state[i]] << "\" " <<
6097  hist_tool_counts[i] << "\n";
6098  }
6099 
6100  if (fn_total_hist != "")
6101  {
6102  std::ofstream file_total(fn_total_hist, std::ios_base::out);
6103 
6104  // Repeat the same error if the file doesn't exists
6105  if (!file_total)
6106  {
6107  throw std::runtime_error(
6108  "Could not open file \"" + fn_total_hist +
6109  "\" for writing.")
6110  ;
6111  }
6112 
6113  file_total <<
6114  #ifdef EPI_DEBUG
6115  "thread " <<
6116  #endif
6117  "date " << "nviruses " << "state " << "counts\n";
6118 
6119  for (epiworld_fast_uint i = 0; i < hist_total_date.size(); ++i)
6120  file_total <<
6121  #ifdef EPI_DEBUG
6122  EPI_GET_THREAD_ID() << " " <<
6123  #endif
6124  hist_total_date[i] << " " <<
6125  hist_total_nviruses_active[i] << " \"" <<
6126  model->states_labels[hist_total_state[i]] << "\" " <<
6127  hist_total_counts[i] << "\n";
6128  }
6129 
6130  if (fn_transmission != "")
6131  {
6132  std::ofstream file_transmission(fn_transmission, std::ios_base::out);
6133 
6134  // Repeat the same error if the file doesn't exists
6135  if (!file_transmission)
6136  {
6137  throw std::runtime_error(
6138  "Could not open file \"" + fn_transmission +
6139  "\" for writing.")
6140  ;
6141  }
6142 
6143  file_transmission <<
6144  #ifdef EPI_DEBUG
6145  "thread " <<
6146  #endif
6147  "date " << "virus_id virus " << "source_exposure_date " << "source " << "target\n";
6148 
6149  for (epiworld_fast_uint i = 0; i < transmission_target.size(); ++i)
6150  file_transmission <<
6151  #ifdef EPI_DEBUG
6152  EPI_GET_THREAD_ID() << " " <<
6153  #endif
6154  transmission_date[i] << " " <<
6155  transmission_virus[i] << " \"" <<
6156  virus_name[transmission_virus[i]] << "\" " <<
6157  transmission_source_exposure_date[i] << " " <<
6158  transmission_source[i] << " " <<
6159  transmission_target[i] << "\n";
6160 
6161  }
6162 
6163  if (fn_transition != "")
6164  {
6165  std::ofstream file_transition(fn_transition, std::ios_base::out);
6166 
6167  // Repeat the same error if the file doesn't exists
6168  if (!file_transition)
6169  {
6170  throw std::runtime_error(
6171  "Could not open file \"" + fn_transition +
6172  "\" for writing.")
6173  ;
6174  }
6175 
6176  file_transition <<
6177  #ifdef EPI_DEBUG
6178  "thread " <<
6179  #endif
6180  "date " << "from " << "to " << "counts\n";
6181 
6182  int ns = model->nstates;
6183 
6184  for (int i = 0; i <= model->today(); ++i)
6185  {
6186 
6187  for (int from = 0u; from < ns; ++from)
6188  {
6189  for (int to = 0u; to < ns; ++to)
6190  {
6191  // Skipping the zeros
6192  auto counts = hist_transition_matrix[
6193  i * (ns * ns) + to * ns + from
6194  ];
6195 
6196  if (counts == 0)
6197  continue;
6198 
6199  file_transition <<
6200  #ifdef EPI_DEBUG
6201  EPI_GET_THREAD_ID() << " " <<
6202  #endif
6203  i << " \"" <<
6204  model->states_labels[from] << "\" \"" <<
6205  model->states_labels[to] << "\" " <<
6206  counts << "\n";
6207  }
6208  }
6209 
6210  }
6211 
6212  }
6213 
6214  if (fn_reproductive_number != "")
6215  get_reproductive_number(fn_reproductive_number);
6216 
6217  if (fn_generation_time != "")
6218  get_generation_time(fn_generation_time);
6219 
6220 }
6221 
6222 template<typename TSeq>
6223 inline void DataBase<TSeq>::record_transmission(
6224  int i,
6225  int j,
6226  int virus,
6227  int i_expo_date
6228 ) {
6229 
6230  transmission_date.push_back(model->today());
6231  transmission_source.push_back(i);
6232  transmission_target.push_back(j);
6233  transmission_virus.push_back(virus);
6234  transmission_source_exposure_date.push_back(i_expo_date);
6235 
6236 }
6237 
6238 template<typename TSeq>
6239 inline size_t DataBase<TSeq>::get_n_viruses() const
6240 {
6241  return virus_id.size();
6242 }
6243 
6244 template<typename TSeq>
6245 inline size_t DataBase<TSeq>::get_n_tools() const
6246 {
6247  return tool_id.size();
6248 }
6249 
6250 
6251 template<typename TSeq>
6252 inline void DataBase<TSeq>::set_user_data(
6253  std::vector< std::string > names
6254 )
6255 {
6256  user_data = UserData<TSeq>(names);
6257  user_data.model = model;
6258 }
6259 
6260 template<typename TSeq>
6261 inline void DataBase<TSeq>::add_user_data(
6262  std::vector< epiworld_double > x
6263 )
6264 {
6265 
6266  user_data.add(x);
6267 
6268 }
6269 
6270 template<typename TSeq>
6271 inline void DataBase<TSeq>::add_user_data(
6272  epiworld_fast_uint k,
6273  epiworld_double x
6274 )
6275 {
6276 
6277  user_data.add(k, x);
6278 
6279 }
6280 
6281 template<typename TSeq>
6282 inline UserData<TSeq> & DataBase<TSeq>::get_user_data()
6283 {
6284  return user_data;
6285 }
6286 
6287 template<typename TSeq>
6288 inline MapVec_type<int,int> DataBase<TSeq>::get_reproductive_number()
6289 const {
6290 
6291  // Checking size
6292  MapVec_type<int,int> map;
6293 
6294  // Number of digits of maxid
6295  for (size_t i = 0u; i < transmission_date.size(); ++i)
6296  {
6297  // Fabricating id
6298  std::vector< int > h = {
6299  transmission_virus[i],
6300  transmission_source[i],
6301  transmission_source_exposure_date[i]
6302  };
6303 
6304  // Adding to counter
6305  if (map.find(h) == map.end())
6306  map[h] = 1;
6307  else
6308  map[h]++;
6309 
6310  // The target is added
6311  std::vector< int > h_target = {
6312  transmission_virus[i],
6313  transmission_target[i],
6314  transmission_date[i]
6315  };
6316 
6317  map[h_target] = 0;
6318 
6319  }
6320 
6321  return map;
6322 
6323 }
6324 
6325 template<typename TSeq>
6326 inline void DataBase<TSeq>::get_reproductive_number(
6327  std::string fn
6328 ) const {
6329 
6330 
6331  auto map = get_reproductive_number();
6332 
6333  std::ofstream fn_file(fn, std::ios_base::out);
6334 
6335  // Repeat the same error if the file doesn't exists
6336  if (!fn_file)
6337  {
6338  throw std::runtime_error(
6339  "Could not open file \"" + fn +
6340  "\" for writing.")
6341  ;
6342  }
6343 
6344  fn_file <<
6345  #ifdef EPI_DEBUG
6346  "thread " <<
6347  #endif
6348  "virus_id virus source source_exposure_date rt\n";
6349 
6350 
6351  for (auto & m : map)
6352  fn_file <<
6353  #ifdef EPI_DEBUG
6354  EPI_GET_THREAD_ID() << " " <<
6355  #endif
6356  m.first[0u] << " \"" <<
6357  virus_name[m.first[0u]] << "\" " <<
6358  m.first[1u] << " " <<
6359  m.first[2u] << " " <<
6360  m.second << "\n";
6361 
6362  return;
6363 
6364 }
6365 
6366 template<typename TSeq>
6367 inline std::vector< epiworld_double > DataBase<TSeq>::get_transition_probability(
6368  bool print,
6369  bool normalize
6370 ) const {
6371 
6372  const auto& states_labels = model->get_states();
6373  size_t n_state = states_labels.size();
6374  size_t n_days = model->get_ndays();
6375  std::vector< epiworld_double > res(n_state * n_state, 0.0);
6376  std::vector< epiworld_double > rowsums(n_state, 0.0);
6377 
6378  for (size_t t = 0; t < n_days; ++t)
6379  {
6380 
6381  for (size_t s_i = 0; s_i < n_state; ++s_i)
6382  {
6383 
6384  for (size_t s_j = 0u; s_j < n_state; ++s_j)
6385  {
6386  res[s_i + s_j * n_state] += (
6387  hist_transition_matrix[
6388  s_i + s_j * n_state +
6389  t * (n_state * n_state)
6390  ]
6391  );
6392 
6393  rowsums[s_i] += hist_transition_matrix[
6394  s_i + s_j * n_state +
6395  t * (n_state * n_state)
6396  ];
6397 
6398  }
6399 
6400  }
6401 
6402  }
6403 
6404  if (normalize)
6405  {
6406  for (size_t s_i = 0; s_i < n_state; ++s_i)
6407  {
6408  // Nothing to normalize if the row is zero
6409  if (rowsums[s_i] == 0)
6410  continue;
6411 
6412  for (size_t s_j = 0; s_j < n_state; ++s_j)
6413  res[s_i + s_j * n_state] /= rowsums[s_i];
6414  }
6415  }
6416 
6417  if (print)
6418  {
6419 
6420  size_t nchar = 0u;
6421  for (auto & l : states_labels)
6422  if (l.length() > nchar)
6423  nchar = l.length();
6424 
6425  std::string fmt = " - %-" + std::to_string(nchar) + "s";
6426 
6427  std::string fmt_entry = " % 4.2f";
6428  if (!normalize)
6429  {
6430  nchar = 0u;
6431  for (auto & l: res)
6432  {
6433  std::string tmp = std::to_string(l);
6434  if (tmp.length() > nchar)
6435  nchar = tmp.length();
6436  }
6437 
6438  fmt_entry = " % " + std::to_string(nchar) + ".0f";
6439  }
6440 
6441 
6442  printf_epiworld("\nTransition Probabilities:\n");
6443  for (size_t s_i = 0u; s_i < n_state; ++s_i)
6444  {
6445  printf_epiworld(fmt.c_str(), states_labels[s_i].c_str());
6446  for (size_t s_j = 0u; s_j < n_state; ++s_j)
6447  {
6448  if (
6449  std::isnan(res[s_i + s_j * n_state]) ||
6450  (res[s_i + s_j * n_state] < 1e-10)
6451  )
6452  {
6453  printf_epiworld(" -");
6454  } else {
6455  printf_epiworld(
6456  fmt_entry.c_str(), res[s_i + s_j * n_state]
6457  );
6458  }
6459  }
6460  printf_epiworld("\n");
6461  }
6462 
6463  printf_epiworld("\n");
6464 
6465  }
6466 
6467  return res;
6468 
6469 
6470 }
6471 
6472 #define VECT_MATCH(a, b, c) \
6473  EPI_DEBUG_FAIL_AT_TRUE(a.size() != b.size(), c) \
6474  for (size_t __i = 0u; __i < a.size(); ++__i) \
6475  {\
6476  EPI_DEBUG_FAIL_AT_TRUE(a[__i] != b[__i], c) \
6477  }
6478 
6479 template<>
6480 inline bool DataBase<std::vector<int>>::operator==(const DataBase<std::vector<int>> & other) const
6481 {
6482  VECT_MATCH(
6483  virus_name, other.virus_name,
6484  "DataBase:: virus_name don't match"
6485  )
6486 
6487  EPI_DEBUG_FAIL_AT_TRUE(
6488  virus_sequence.size() != other.virus_sequence.size(),
6489  "DataBase:: virus_sequence don't match."
6490  )
6491 
6492  for (size_t i = 0u; i < virus_sequence.size(); ++i)
6493  {
6494  VECT_MATCH(
6495  virus_sequence[i], other.virus_sequence[i],
6496  "DataBase:: virus_sequence[i] don't match"
6497  )
6498  }
6499 
6500  VECT_MATCH(
6501  virus_origin_date,
6502  other.virus_origin_date,
6503  "DataBase:: virus_origin_date[i] don't match"
6504  )
6505 
6506  VECT_MATCH(
6507  virus_parent_id,
6508  other.virus_parent_id,
6509  "DataBase:: virus_parent_id[i] don't match"
6510  )
6511 
6512  VECT_MATCH(
6513  tool_name,
6514  other.tool_name,
6515  "DataBase:: tool_name[i] don't match"
6516  )
6517 
6518  VECT_MATCH(
6519  tool_sequence,
6520  other.tool_sequence,
6521  "DataBase:: tool_sequence[i] don't match"
6522  )
6523 
6524  VECT_MATCH(
6525  tool_origin_date,
6526  other.tool_origin_date,
6527  "DataBase:: tool_origin_date[i] don't match"
6528  )
6529 
6530 
6531  EPI_DEBUG_FAIL_AT_TRUE(
6532  sampling_freq != other.sampling_freq,
6533  "DataBase:: sampling_freq don't match."
6534  )
6535 
6536  // Variants history
6537  VECT_MATCH(
6538  hist_virus_date,
6539  other.hist_virus_date,
6540  "DataBase:: hist_virus_date[i] don't match"
6541  )
6542 
6543  VECT_MATCH(
6544  hist_virus_id,
6545  other.hist_virus_id,
6546  "DataBase:: hist_virus_id[i] don't match"
6547  )
6548 
6549  VECT_MATCH(
6550  hist_virus_state,
6551  other.hist_virus_state,
6552  "DataBase:: hist_virus_state[i] don't match"
6553  )
6554 
6555  VECT_MATCH(
6556  hist_virus_counts,
6557  other.hist_virus_counts,
6558  "DataBase:: hist_virus_counts[i] don't match"
6559  )
6560 
6561  // Tools history
6562  VECT_MATCH(
6563  hist_tool_date,
6564  other.hist_tool_date,
6565  "DataBase:: hist_tool_date[i] don't match"
6566  )
6567 
6568  VECT_MATCH(
6569  hist_tool_id,
6570  other.hist_tool_id,
6571  "DataBase:: hist_tool_id[i] don't match"
6572  )
6573 
6574  VECT_MATCH(
6575  hist_tool_state,
6576  other.hist_tool_state,
6577  "DataBase:: hist_tool_state[i] don't match"
6578  )
6579 
6580  VECT_MATCH(
6581  hist_tool_counts,
6582  other.hist_tool_counts,
6583  "DataBase:: hist_tool_counts[i] don't match"
6584  )
6585 
6586  // Overall hist
6587  VECT_MATCH(
6588  hist_total_date,
6589  other.hist_total_date,
6590  "DataBase:: hist_total_date[i] don't match"
6591  )
6592 
6593  VECT_MATCH(
6594  hist_total_nviruses_active,
6595  other.hist_total_nviruses_active,
6596  "DataBase:: hist_total_nviruses_active[i] don't match"
6597  )
6598 
6599  VECT_MATCH(
6600  hist_total_state,
6601  other.hist_total_state,
6602  "DataBase:: hist_total_state[i] don't match"
6603  )
6604 
6605  VECT_MATCH(
6606  hist_total_counts,
6607  other.hist_total_counts,
6608  "DataBase:: hist_total_counts[i] don't match"
6609  )
6610 
6611  VECT_MATCH(
6612  hist_transition_matrix,
6613  other.hist_transition_matrix,
6614  "DataBase:: hist_transition_matrix[i] don't match"
6615  )
6616 
6617  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
6618  EPI_DEBUG_FAIL_AT_TRUE(
6619  today_virus.size() != other.today_virus.size(),
6620  "DataBase:: today_virus don't match."
6621  )
6622 
6623  for (size_t i = 0u; i < today_virus.size(); ++i)
6624  {
6625  VECT_MATCH(
6626  today_virus[i], other.today_virus[i],
6627  "DataBase:: today_virus[i] don't match"
6628  )
6629  }
6630 
6631  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
6632  if (today_tool.size() != other.today_tool.size())
6633  return false;
6634 
6635  for (size_t i = 0u; i < today_tool.size(); ++i)
6636  {
6637  VECT_MATCH(
6638  today_tool[i], other.today_tool[i],
6639  "DataBase:: today_tool[i] don't match"
6640  )
6641  }
6642 
6643  // {Susceptible, Infected, etc.}
6644  VECT_MATCH(
6645  today_total, other.today_total,
6646  "DataBase:: today_total don't match"
6647  )
6648 
6649  // Totals
6650  EPI_DEBUG_FAIL_AT_TRUE(
6651  today_total_nviruses_active != other.today_total_nviruses_active,
6652  "DataBase:: today_total_nviruses_active don't match."
6653  )
6654 
6655  // Transmission network
6656  VECT_MATCH(
6657  transmission_date,
6658  other.transmission_date, ///< Date of the transmission eve,
6659  "DataBase:: transmission_date[i] don't match"
6660  )
6661 
6662  VECT_MATCH(
6663  transmission_source,
6664  other.transmission_source, ///< Id of the sour,
6665  "DataBase:: transmission_source[i] don't match"
6666  )
6667 
6668  VECT_MATCH(
6669  transmission_target,
6670  other.transmission_target, ///< Id of the targ,
6671  "DataBase:: transmission_target[i] don't match"
6672  )
6673 
6674  VECT_MATCH(
6675  transmission_virus,
6676  other.transmission_virus, ///< Id of the varia,
6677  "DataBase:: transmission_virus[i] don't match"
6678  )
6679 
6680  VECT_MATCH(
6681  transmission_source_exposure_date,
6682  other.transmission_source_exposure_date, ///< Date when the source acquired the varia,
6683  "DataBase:: transmission_source_exposure_date[i] don't match"
6684  )
6685 
6686 
6687  VECT_MATCH(
6688  transition_matrix,
6689  other.transition_matrix,
6690  "DataBase:: transition_matrix[i] don't match"
6691  )
6692 
6693 
6694  return true;
6695 
6696 }
6697 
6698 template<typename TSeq>
6699 inline bool DataBase<TSeq>::operator==(const DataBase<TSeq> & other) const
6700 {
6701  VECT_MATCH(
6702  virus_name,
6703  other.virus_name,
6704  "DataBase:: virus_name[i] don't match"
6705  )
6706 
6707  VECT_MATCH(
6708  virus_sequence,
6709  other.virus_sequence,
6710  "DataBase:: virus_sequence[i] don't match"
6711  )
6712 
6713  VECT_MATCH(
6714  virus_origin_date,
6715  other.virus_origin_date,
6716  "DataBase:: virus_origin_date[i] don't match"
6717  )
6718 
6719  VECT_MATCH(
6720  virus_parent_id,
6721  other.virus_parent_id,
6722  "DataBase:: virus_parent_id[i] don't match"
6723  )
6724 
6725  VECT_MATCH(
6726  tool_name,
6727  other.tool_name,
6728  "DataBase:: tool_name[i] don't match"
6729  )
6730 
6731  VECT_MATCH(
6732  tool_sequence,
6733  other.tool_sequence,
6734  "DataBase:: tool_sequence[i] don't match"
6735  )
6736 
6737  VECT_MATCH(
6738  tool_origin_date,
6739  other.tool_origin_date,
6740  "DataBase:: tool_origin_date[i] don't match"
6741  )
6742 
6743 
6744  EPI_DEBUG_FAIL_AT_TRUE(
6745  sampling_freq != other.sampling_freq,
6746  "DataBase:: sampling_freq don't match."
6747  )
6748 
6749  // Variants history
6750  VECT_MATCH(
6751  hist_virus_date,
6752  other.hist_virus_date,
6753  "DataBase:: hist_virus_date[i] don't match"
6754  )
6755 
6756  VECT_MATCH(
6757  hist_virus_id,
6758  other.hist_virus_id,
6759  "DataBase:: hist_virus_id[i] don't match"
6760  )
6761 
6762  VECT_MATCH(
6763  hist_virus_state,
6764  other.hist_virus_state,
6765  "DataBase:: hist_virus_state[i] don't match"
6766  )
6767 
6768  VECT_MATCH(
6769  hist_virus_counts,
6770  other.hist_virus_counts,
6771  "DataBase:: hist_virus_counts[i] don't match"
6772  )
6773 
6774  // Tools history
6775  VECT_MATCH(
6776  hist_tool_date,
6777  other.hist_tool_date,
6778  "DataBase:: hist_tool_date[i] don't match"
6779  )
6780 
6781  VECT_MATCH(
6782  hist_tool_id,
6783  other.hist_tool_id,
6784  "DataBase:: hist_tool_id[i] don't match"
6785  )
6786 
6787  VECT_MATCH(
6788  hist_tool_state,
6789  other.hist_tool_state,
6790  "DataBase:: hist_tool_state[i] don't match"
6791  )
6792 
6793  VECT_MATCH(
6794  hist_tool_counts,
6795  other.hist_tool_counts,
6796  "DataBase:: hist_tool_counts[i] don't match"
6797  )
6798 
6799  // Overall hist
6800  VECT_MATCH(
6801  hist_total_date,
6802  other.hist_total_date,
6803  "DataBase:: hist_total_date[i] don't match"
6804  )
6805 
6806  VECT_MATCH(
6807  hist_total_nviruses_active,
6808  other.hist_total_nviruses_active,
6809  "DataBase:: hist_total_nviruses_active[i] don't match"
6810  )
6811 
6812  VECT_MATCH(
6813  hist_total_state,
6814  other.hist_total_state,
6815  "DataBase:: hist_total_state[i] don't match"
6816  )
6817 
6818  VECT_MATCH(
6819  hist_total_counts,
6820  other.hist_total_counts,
6821  "DataBase:: hist_total_counts[i] don't match"
6822  )
6823 
6824  VECT_MATCH(
6825  hist_transition_matrix,
6826  other.hist_transition_matrix,
6827  "DataBase:: hist_transition_matrix[i] don't match"
6828  )
6829 
6830  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
6831  EPI_DEBUG_FAIL_AT_TRUE(
6832  today_virus.size() != other.today_virus.size(),
6833  "DataBase:: today_virus.size() don't match."
6834  )
6835 
6836  for (size_t i = 0u; i < today_virus.size(); ++i)
6837  {
6838  VECT_MATCH(
6839  today_virus[i], other.today_virus[i],
6840  "DataBase:: today_virus[i] don't match"
6841  )
6842  }
6843 
6844  // {Variant 1: {state 1, state 2, etc.}, Variant 2: {...}, ...}
6845  EPI_DEBUG_FAIL_AT_TRUE(
6846  today_tool.size() != other.today_tool.size(),
6847  "DataBase:: today_tool.size() don't match."
6848  )
6849 
6850  for (size_t i = 0u; i < today_tool.size(); ++i)
6851  {
6852  VECT_MATCH(
6853  today_tool[i], other.today_tool[i],
6854  "DataBase:: today_tool[i] don't match"
6855  )
6856  }
6857 
6858  // {Susceptible, Infected, etc.}
6859  VECT_MATCH(
6860  today_total, other.today_total,
6861  "DataBase:: today_total[i] don't match"
6862  )
6863 
6864  // Totals
6865  EPI_DEBUG_FAIL_AT_TRUE(
6866  today_total_nviruses_active != other.today_total_nviruses_active,
6867  "DataBase:: today_total_nviruses_active don't match."
6868  )
6869 
6870  // Transmission network
6871  VECT_MATCH( ///< Date of the transmission eve
6872  transmission_date,
6873  other.transmission_date,
6874  "DataBase:: transmission_date[i] don't match"
6875  )
6876 
6877  VECT_MATCH( ///< Id of the sour
6878  transmission_source,
6879  other.transmission_source,
6880  "DataBase:: transmission_source[i] don't match"
6881  )
6882 
6883  VECT_MATCH( ///< Id of the targ
6884  transmission_target,
6885  other.transmission_target,
6886  "DataBase:: transmission_target[i] don't match"
6887  )
6888 
6889  VECT_MATCH( ///< Id of the varia
6890  transmission_virus,
6891  other.transmission_virus,
6892  "DataBase:: transmission_virus[i] don't match"
6893  )
6894 
6895  VECT_MATCH( ///< Date when the source acquired the varia
6896  transmission_source_exposure_date,
6897  other.transmission_source_exposure_date,
6898  "DataBase:: transmission_source_exposure_date[i] don't match"
6899  )
6900 
6901  VECT_MATCH(
6902  transition_matrix,
6903  other.transition_matrix,
6904  "DataBase:: transition_matrix[i] don't match"
6905  )
6906 
6907  return true;
6908 
6909 }
6910 
6911 template<typename TSeq>
6912 inline void DataBase<TSeq>::get_generation_time(
6913  std::vector< int > & agent_id,
6914  std::vector< int > & virus_id,
6915  std::vector< int > & time,
6916  std::vector< int > & gentime
6917 ) const {
6918 
6919  size_t nevents = transmission_date.size();
6920 
6921  agent_id.reserve(nevents);
6922  virus_id.reserve(nevents);
6923  time.reserve(nevents);
6924  gentime.reserve(nevents);
6925 
6926  // Iterating through the individuals
6927  for (size_t i = 0u; i < nevents; ++i)
6928  {
6929  int agent_id_i = transmission_target[i];
6930  agent_id.push_back(agent_id_i);
6931  virus_id.push_back(transmission_virus[i]);
6932  time.push_back(transmission_date[i]);
6933 
6934  bool found = false;
6935  for (size_t j = i; j < nevents; ++j)
6936  {
6937 
6938  if (transmission_source[j] == agent_id_i)
6939  {
6940  gentime.push_back(transmission_date[j] - time[i]);
6941  found = true;
6942  break;
6943  }
6944 
6945  }
6946 
6947  // If there's no transmission, we set the generation time to
6948  // minus 1;
6949  if (!found)
6950  gentime.push_back(-1);
6951 
6952  }
6953 
6954  agent_id.shrink_to_fit();
6955  virus_id.shrink_to_fit();
6956  time.shrink_to_fit();
6957  gentime.shrink_to_fit();
6958 
6959  return;
6960 
6961 }
6962 
6963 template<typename TSeq>
6964 inline void DataBase<TSeq>::get_generation_time(
6965  std::string fn
6966 ) const
6967 {
6968 
6969  std::vector< int > agent_id;
6970  std::vector< int > virus_id;
6971  std::vector< int > time;
6972  std::vector< int > gentime;
6973 
6974  get_generation_time(agent_id, virus_id, time, gentime);
6975 
6976  std::ofstream fn_file(fn, std::ios_base::out);
6977 
6978  // Throw an error if the file doesn't exists using throw
6979  if (!fn_file)
6980  {
6981  throw std::runtime_error(
6982  "DataBase::get_generation_time: "
6983  "Cannot open file " + fn + "."
6984  );
6985  }
6986 
6987 
6988 
6989  fn_file <<
6990  #ifdef EPI_DEBUG
6991  "thread " <<
6992  #endif
6993  "virus source source_exposure_date gentime\n";
6994 
6995  size_t n = agent_id.size();
6996  for (size_t i = 0u; i < n; ++i)
6997  fn_file <<
6998  #ifdef EPI_DEBUG
6999  EPI_GET_THREAD_ID() << " " <<
7000  #endif
7001  virus_id[i] << " " <<
7002  agent_id[i] << " " <<
7003  time[i] << " " <<
7004  gentime[i] << "\n";
7005 
7006  return;
7007 
7008 }
7009 
7010 #undef VECT_MATCH
7011 
7012 #endif
7013 /*//////////////////////////////////////////////////////////////////////////////
7015 
7016  End of -include/epiworld/database-meat.hpp-
7017 
7020 
7021 
7022 /*//////////////////////////////////////////////////////////////////////////////
7024 
7025  Start of -include/epiworld/adjlist-bones.hpp-
7026 
7029 
7030 
7031 #ifndef EPIWORLD_ADJLIST_BONES_HPP
7032 #define EPIWORLD_ADJLIST_BONES_HPP
7033 
7034 class AdjList {
7035 private:
7036 
7037  std::vector<std::map<int, int>> dat;
7038  bool directed;
7039  epiworld_fast_uint N = 0;
7040  epiworld_fast_uint E = 0;
7041 
7042 public:
7043 
7044  AdjList() {};
7045 
7057  AdjList(
7058  const std::vector< int > & source,
7059  const std::vector< int > & target,
7060  int size,
7061  bool directed
7062  );
7063 
7064  AdjList(AdjList && a); // Move constructor
7065  AdjList(const AdjList & a); // Copy constructor
7066  AdjList& operator=(const AdjList& a);
7067 
7068 
7079  void read_edgelist(
7080  std::string fn,
7081  int size,
7082  int skip = 0,
7083  bool directed = true
7084  );
7085 
7086  std::map<int, int> operator()(
7087  epiworld_fast_uint i
7088  ) const;
7089 
7090  void print(epiworld_fast_uint limit = 20u) const;
7091  size_t vcount() const; ///< Number of vertices/nodes in the network.
7092  size_t ecount() const; ///< Number of edges/arcs/ties in the network.
7093 
7094  std::vector<std::map<int,int>> & get_dat() {
7095  return dat;
7096  };
7097 
7098  bool is_directed() const; ///< `true` if the network is directed.
7099 
7100 };
7101 
7102 
7103 #endif
7104 
7105 /*//////////////////////////////////////////////////////////////////////////////
7107 
7108  End of -include/epiworld/adjlist-bones.hpp-
7109 
7112 
7113 
7114 /*//////////////////////////////////////////////////////////////////////////////
7116 
7117  Start of -include/epiworld/adjlist-meat.hpp-
7118 
7121 
7122 
7123 #ifndef EPIWORLD_ADJLIST_MEAT_HPP
7124 #define EPIWORLD_ADJLIST_MEAT_HPP
7125 
7126 inline AdjList::AdjList(
7127  const std::vector< int > & source,
7128  const std::vector< int > & target,
7129  int size,
7130  bool directed
7131 ) : directed(directed) {
7132 
7133 
7134  dat.resize(size, std::map<int,int>({}));
7135  int max_id = size - 1;
7136 
7137  int i,j;
7138  for (int m = 0; m < static_cast<int>(source.size()); ++m)
7139  {
7140 
7141  i = source[m];
7142  j = target[m];
7143 
7144  if (i > max_id)
7145  throw std::range_error(
7146  "The source["+std::to_string(m)+"] = " + std::to_string(i) +
7147  " is above the max_id " + std::to_string(max_id)
7148  );
7149 
7150  if (j > max_id)
7151  throw std::range_error(
7152  "The target["+std::to_string(m)+"] = " + std::to_string(j) +
7153  " is above the max_id " + std::to_string(max_id)
7154  );
7155 
7156  // Adding nodes
7157  if (dat[i].find(j) == dat[i].end())
7158  dat[i].insert(std::pair<int, int>(j, 1u));
7159  else
7160  dat[i][j]++;
7161 
7162  if (!directed)
7163  {
7164 
7165  if (dat[j].find(i) == dat[j].end())
7166  dat[j].insert(std::pair<int, int>(i, 1u));
7167  else
7168  dat[j][i]++;
7169 
7170  }
7171 
7172  E++;
7173 
7174  }
7175 
7176  N = size;
7177 
7178  return;
7179 
7180 }
7181 
7182 
7183 inline AdjList::AdjList(AdjList && a) :
7184  dat(std::move(a.dat)),
7185  directed(a.directed),
7186  N(a.N),
7187  E(a.E)
7188 {
7189 
7190 }
7191 
7192 inline AdjList::AdjList(const AdjList & a) :
7193  dat(a.dat),
7194  directed(a.directed),
7195  N(a.N),
7196  E(a.E)
7197 {
7198 
7199 }
7200 
7201 inline AdjList& AdjList::operator=(const AdjList& a)
7202 {
7203  if (this == &a)
7204  return *this;
7205 
7206  this->dat = a.dat;
7207  this->directed = a.directed;
7208  this->N = a.N;
7209  this->E = a.E;
7210 
7211  return *this;
7212 }
7213 
7214 inline void AdjList::read_edgelist(
7215  std::string fn,
7216  int size,
7217  int skip,
7218  bool directed
7219 ) {
7220 
7221  int i,j;
7222  std::ifstream filei(fn);
7223 
7224  if (!filei)
7225  throw std::logic_error("The file " + fn + " was not found.");
7226 
7227  int linenum = 0;
7228  std::vector< int > source_;
7229  std::vector< int > target_;
7230 
7231  source_.reserve(1e5);
7232  target_.reserve(1e5);
7233 
7234  int max_id = size - 1;
7235 
7236  while (!filei.eof())
7237  {
7238 
7239  if (linenum++ < skip)
7240  continue;
7241 
7242  filei >> i >> j;
7243 
7244  // Looking for exceptions
7245  if (filei.bad())
7246  throw std::logic_error(
7247  "I/O error while reading the file " +
7248  fn
7249  );
7250 
7251  if (filei.fail())
7252  break;
7253 
7254  if (i > max_id)
7255  throw std::range_error(
7256  "The source["+std::to_string(linenum)+"] = " + std::to_string(i) +
7257  " is above the max_id " + std::to_string(max_id)
7258  );
7259 
7260  if (j > max_id)
7261  throw std::range_error(
7262  "The target["+std::to_string(linenum)+"] = " + std::to_string(j) +
7263  " is above the max_id " + std::to_string(max_id)
7264  );
7265 
7266  source_.push_back(i);
7267  target_.push_back(j);
7268 
7269  }
7270 
7271  // Now using the right constructor
7272  *this = AdjList(source_, target_, size, directed);
7273 
7274  return;
7275 
7276 }
7277 
7278 inline std::map<int,int> AdjList::operator()(
7279  epiworld_fast_uint i
7280  ) const {
7281 
7282  if (i >= N)
7283  throw std::range_error(
7284  "The vertex id " + std::to_string(i) + " is not in the network."
7285  );
7286 
7287  return dat[i];
7288 
7289 }
7290 
7291 inline void AdjList::print(epiworld_fast_uint limit) const {
7292 
7293 
7294  epiworld_fast_uint counter = 0;
7295  printf_epiworld("Nodeset:\n");
7296  int i = -1;
7297  for (auto & n : dat)
7298  {
7299 
7300  if (counter++ > limit)
7301  break;
7302 
7303  printf_epiworld(" % 3i: {", ++i);
7304  int niter = 0;
7305  for (auto n_n : n)
7306  if (++niter < static_cast<int>(n.size()))
7307  {
7308  printf_epiworld("%i, ", static_cast<int>(n_n.first));
7309  }
7310  else {
7311  printf_epiworld("%i}\n", static_cast<int>(n_n.first));
7312  }
7313  }
7314 
7315  if (limit < dat.size())
7316  {
7317  printf_epiworld(
7318  " (... skipping %i records ...)\n",
7319  static_cast<int>(dat.size() - limit)
7320  );
7321  }
7322 
7323 }
7324 
7325 inline size_t AdjList::vcount() const
7326 {
7327  return N;
7328 }
7329 
7330 inline size_t AdjList::ecount() const
7331 {
7332  return E;
7333 }
7334 
7335 inline bool AdjList::is_directed() const {
7336 
7337  if (dat.size() == 0u)
7338  throw std::logic_error("The edgelist is empty.");
7339 
7340  return directed;
7341 
7342 }
7343 
7344 #endif
7345 /*//////////////////////////////////////////////////////////////////////////////
7347 
7348  End of -include/epiworld/adjlist-meat.hpp-
7349 
7352 
7353 
7354 
7355 /*//////////////////////////////////////////////////////////////////////////////
7357 
7358  Start of -include/epiworld/randgraph.hpp-
7359 
7362 
7363 
7364 #ifndef EPIWORLD_RANDGRA
7365 #define EPIWORLD_RANDGRA
7366 
7367 template<typename TSeq>
7368 class Model;
7369 
7370 template<typename TSeq>
7371 class Agent;
7372 
7373 class AdjList;
7374 
7375 
7376 template<typename TSeq, typename TDat>
7377 inline void rewire_degseq(
7378  TDat * agents,
7379  Model<TSeq> * model,
7380  epiworld_double proportion
7381  );
7382 
7383 template<typename TSeq = EPI_DEFAULT_TSEQ>
7384 inline void rewire_degseq(
7385  std::vector< Agent<TSeq> > * agents,
7386  Model<TSeq> * model,
7387  epiworld_double proportion
7388  )
7389 {
7390 
7391  #ifdef EPI_DEBUG
7392  std::vector< int > _degree0(agents->size(), 0);
7393  for (size_t i = 0u; i < _degree0.size(); ++i)
7394  _degree0[i] = model->get_agents()[i].get_neighbors().size();
7395  #endif
7396 
7397  // Identifying individuals with degree > 0
7398  std::vector< epiworld_fast_uint > non_isolates;
7399  std::vector< epiworld_double > weights;
7400  epiworld_double nedges = 0.0;
7401 
7402  for (epiworld_fast_uint i = 0u; i < agents->size(); ++i)
7403  {
7404  if (agents->operator[](i).get_neighbors().size() > 0u)
7405  {
7406  non_isolates.push_back(i);
7407  epiworld_double wtemp = static_cast<epiworld_double>(
7408  agents->operator[](i).get_neighbors().size()
7409  );
7410  weights.push_back(wtemp);
7411  nedges += wtemp;
7412  }
7413  }
7414 
7415  if (non_isolates.size() == 0u)
7416  throw std::logic_error("The graph is completely disconnected.");
7417 
7418  // Cumulative probs
7419  weights[0u] /= nedges;
7420  for (epiworld_fast_uint i = 1u; i < non_isolates.size(); ++i)
7421  {
7422  weights[i] /= nedges;
7423  weights[i] += weights[i - 1u];
7424  }
7425 
7426  // Only swap if needed
7427  epiworld_fast_uint N = non_isolates.size();
7428  epiworld_double prob;
7429  int nrewires = floor(proportion * nedges);
7430  while (nrewires-- > 0)
7431  {
7432 
7433  // Picking egos
7434  prob = model->runif();
7435  int id0 = N - 1;
7436  for (epiworld_fast_uint i = 0u; i < N; ++i)
7437  if (prob <= weights[i])
7438  {
7439  id0 = i;
7440  break;
7441  }
7442 
7443  prob = model->runif();
7444  int id1 = N - 1;
7445  for (epiworld_fast_uint i = 0u; i < N; ++i)
7446  if (prob <= weights[i])
7447  {
7448  id1 = i;
7449  break;
7450  }
7451 
7452  // Correcting for under or overflow.
7453  if (id1 == id0)
7454  id1++;
7455 
7456  if (id1 >= static_cast<int>(N))
7457  id1 = 0;
7458 
7459  Agent<TSeq> & p0 = agents->operator[](non_isolates[id0]);
7460  Agent<TSeq> & p1 = agents->operator[](non_isolates[id1]);
7461 
7462  // Picking alters (relative location in their lists)
7463  // In this case, these are uniformly distributed within the list
7464  int id01 = std::floor(p0.get_n_neighbors() * model->runif());
7465  int id11 = std::floor(p1.get_n_neighbors() * model->runif());
7466 
7467  // Get the actual neighbor IDs that will be swapped
7468  auto neighbors_p0 = p0.get_neighbors();
7469  auto neighbors_p1 = p1.get_neighbors();
7470  size_t neighbor_id_01 = neighbors_p0[id01]->get_id();
7471  size_t neighbor_id_11 = neighbors_p1[id11]->get_id();
7472 
7473  // Check if the swap would create self-loops or invalid configurations
7474  // After swap: p0 will be connected to neighbor_id_11, p1 to neighbor_id_01
7475  // Skip if:
7476  // 1. neighbor_id_01 == neighbor_id_11 (swapping the same neighbor)
7477  // 2. neighbor_id_01 == non_isolates[id1] (p1's new neighbor would be p1 itself)
7478  // 3. neighbor_id_11 == non_isolates[id0] (p0's new neighbor would be p0 itself)
7479  if (neighbor_id_01 == neighbor_id_11 ||
7480  neighbor_id_01 == non_isolates[id1] ||
7481  neighbor_id_11 == non_isolates[id0]) {
7482  continue;
7483  }
7484 
7485  // Check if the swap would create duplicate edges
7486  // After swap: p0 will be connected to neighbor_id_11, p1 to neighbor_id_01
7487  bool would_create_duplicate = false;
7488  for (auto* n : neighbors_p0) {
7489  if (n->get_id() == neighbor_id_11 && n != neighbors_p0[id01]) {
7490  would_create_duplicate = true;
7491  break;
7492  }
7493  }
7494  if (!would_create_duplicate) {
7495  for (auto* n : neighbors_p1) {
7496  if (n->get_id() == neighbor_id_01 && n != neighbors_p1[id11]) {
7497  would_create_duplicate = true;
7498  break;
7499  }
7500  }
7501  }
7502 
7503  if (would_create_duplicate) {
7504  continue; // Skip this rewire attempt
7505  }
7506 
7507  // When rewiring, we need to flip the individuals from the other
7508  // end as well, since we are dealing withi an undirected graph
7509 
7510  // Swap neighbors between the two agents
7511  // Note: id0 and id1 are indices in non_isolates, not agent IDs
7512  model->get_agents()[non_isolates[id0]].swap_neighbors(
7513  model->get_agents()[non_isolates[id1]],
7514  id01,
7515  id11
7516  );
7517 
7518 
7519  }
7520 
7521  #ifdef EPI_DEBUG
7522  for (size_t _i = 0u; _i < _degree0.size(); ++_i)
7523  {
7524  if (_degree0[_i] != static_cast<int>(model->get_agents()[_i].get_n_neighbors()))
7525  throw std::logic_error("[epi-debug] Degree does not match afted rewire_degseq.");
7526  }
7527  #endif
7528 
7529  return;
7530 
7531 }
7532 
7533 template<typename TSeq>
7534 inline void rewire_degseq(
7535  AdjList * agents,
7536  Model<TSeq> * model,
7537  epiworld_double proportion
7538  )
7539 {
7540 
7541  // Identifying individuals with degree > 0
7542  std::vector< epiworld_fast_int > nties(agents->vcount(), 0);
7543 
7544  #ifdef EPI_DEBUG
7545  std::vector< int > _degree0(agents->vcount(), 0);
7546  for (size_t i = 0u; i < _degree0.size(); ++i)
7547  _degree0[i] = agents->get_dat()[i].size();
7548  #endif
7549 
7550  std::vector< int > non_isolates;
7551  non_isolates.reserve(nties.size());
7552 
7553  std::vector< epiworld_double > weights;
7554  weights.reserve(nties.size());
7555 
7556  epiworld_double nedges = 0.0;
7557  auto & dat = agents->get_dat();
7558 
7559  for (size_t i = 0u; i < dat.size(); ++i)
7560  nties[i] += dat[i].size();
7561 
7562  bool directed = agents->is_directed();
7563  for (size_t i = 0u; i < dat.size(); ++i)
7564  {
7565  if (nties[i] > 0)
7566  {
7567  non_isolates.push_back(i);
7568  if (directed)
7569  {
7570  weights.push_back(
7571  static_cast<epiworld_double>(nties[i])
7572  );
7573  nedges += static_cast<epiworld_double>(nties[i]);
7574  }
7575  else {
7576  weights.push_back(
7577  static_cast<epiworld_double>(nties[i])/2.0
7578  );
7579  nedges += static_cast<epiworld_double>(nties[i]) / 2.0;
7580  }
7581  }
7582  }
7583 
7584  if (non_isolates.size() == 0u)
7585  throw std::logic_error("The graph is completely disconnected.");
7586 
7587  // Cumulative probs
7588  weights[0u] /= nedges;
7589  for (epiworld_fast_uint i = 1u; i < non_isolates.size(); ++i)
7590  {
7591  weights[i] /= nedges;
7592  weights[i] += weights[i - 1u];
7593  }
7594 
7595  // Only swap if needed
7596  epiworld_fast_uint N = non_isolates.size();
7597  epiworld_double prob;
7598  int nrewires = floor(proportion * nedges / (
7599  agents->is_directed() ? 1.0 : 2.0
7600  ));
7601 
7602  while (nrewires-- > 0)
7603  {
7604 
7605  // Picking egos
7606  prob = model->runif();
7607  int id0 = N - 1;
7608  for (epiworld_fast_uint i = 0u; i < N; ++i)
7609  if (prob <= weights[i])
7610  {
7611  id0 = i;
7612  break;
7613  }
7614 
7615  prob = model->runif();
7616  int id1 = N - 1;
7617  for (epiworld_fast_uint i = 0u; i < N; ++i)
7618  if (prob <= weights[i])
7619  {
7620  id1 = i;
7621  break;
7622  }
7623 
7624  // Correcting for under or overflow.
7625  if (id1 == id0)
7626  id1++;
7627 
7628  if (id1 >= static_cast<int>(N))
7629  id1 = 0;
7630 
7631  std::map<int,int> & p0 = agents->get_dat()[non_isolates[id0]];
7632  std::map<int,int> & p1 = agents->get_dat()[non_isolates[id1]];
7633 
7634  // Picking alters (relative location in their lists)
7635  // In this case, these are uniformly distributed within the list
7636  int id01 = std::floor(p0.size() * model->runif());
7637  int id11 = std::floor(p1.size() * model->runif());
7638 
7639  // Since it is a map, we need to find the actual ids (positions)
7640  // are not good enough.
7641  int count = 0;
7642  for (auto & n : p0)
7643  if (count++ == id01)
7644  id01 = n.first;
7645 
7646  count = 0;
7647  for (auto & n : p1)
7648  if (count++ == id11)
7649  id11 = n.first;
7650 
7651  // When rewiring, we need to actually swap the edges, not just the weights
7652  // We'll swap edges: (id0, id01) <-> (id1, id11)
7653  // After swap: (id0, id11) and (id1, id01)
7654  // But first, check if the swap would create duplicate or self-loop edges
7655 
7656  // Check for self-loops (new edge would connect node to itself)
7657  if (id01 == non_isolates[id1] || id11 == non_isolates[id0]) {
7658  continue;
7659  }
7660 
7661  // Check for duplicate edges (new edge already exists)
7662  if (p0.find(id11) != p0.end() || p1.find(id01) != p1.end()) {
7663  continue; // Skip this rewire attempt to avoid duplicate edges
7664  }
7665 
7666  // Check if we're trying to swap the same neighbor
7667  if (id01 == id11) {
7668  continue;
7669  }
7670 
7671  // Save the weights before removing edges
7672  int weight_0_01 = p0[id01];
7673  int weight_1_11 = p1[id11];
7674 
7675  // Remove old edges from ego perspectives
7676  p0.erase(id01);
7677  p1.erase(id11);
7678 
7679  // Add new edges from ego perspectives with swapped alters
7680  p0[id11] = weight_0_01;
7681  p1[id01] = weight_1_11;
7682 
7683  // For undirected graphs, also update from alter perspectives
7684  if (!agents->is_directed())
7685  {
7686  std::map<int,int> & p01 = agents->get_dat()[id01];
7687  std::map<int,int> & p11 = agents->get_dat()[id11];
7688 
7689  // Save weights from alter perspectives
7690  int weight_01_0 = p01[non_isolates[id0]];
7691  int weight_11_1 = p11[non_isolates[id1]];
7692 
7693  // Remove old edges from alter perspectives
7694  p01.erase(non_isolates[id0]);
7695  p11.erase(non_isolates[id1]);
7696 
7697  // Add new edges from alter perspectives
7698  p01[non_isolates[id1]] = weight_11_1;
7699  p11[non_isolates[id0]] = weight_01_0;
7700  }
7701 
7702  }
7703 
7704  #ifdef EPI_DEBUG
7705  for (size_t _i = 0u; _i < _degree0.size(); ++_i)
7706  {
7707  if (_degree0[_i] != static_cast<int>(agents->get_dat()[_i].size()))
7708  throw std::logic_error(
7709  "[epi-debug] Degree does not match afted rewire_degseq. " +
7710  std::string("Expected: ") +
7711  std::to_string(_degree0[_i]) +
7712  std::string(", observed: ") +
7713  std::to_string(agents->get_dat()[_i].size())
7714  );
7715  }
7716  #endif
7717 
7718 
7719  return;
7720 
7721 }
7722 
7723 template<typename TSeq>
7724 inline AdjList rgraph_bernoulli(
7725  epiworld_fast_uint n,
7726  epiworld_double p,
7727  bool directed,
7728  Model<TSeq> & model
7729 ) {
7730 
7731  std::vector< int > source;
7732  std::vector< int > target;
7733 
7734  // Checking the density (how many)
7735  std::binomial_distribution<> d(
7736  n * (n - 1.0) / (directed ? 1.0 : 2.0),
7737  p
7738  );
7739 
7740  epiworld_fast_uint m = d(model.get_rand_endgine());
7741 
7742  source.resize(m);
7743  target.resize(m);
7744 
7745  epiworld_fast_uint a,b;
7746  for (epiworld_fast_uint i = 0u; i < m; ++i)
7747  {
7748  a = floor(model.runif() * n);
7749 
7750  if (!directed)
7751  b = floor(model.runif() * a);
7752  else
7753  {
7754  b = floor(model.runif() * n);
7755  if (b == a)
7756  b++;
7757 
7758  if (b >= n)
7759  b = 0u;
7760  }
7761 
7762  source[i] = static_cast<int>(a);
7763  target[i] = static_cast<int>(b);
7764 
7765  }
7766 
7767  AdjList al(source, target, static_cast<int>(n), directed);
7768 
7769  return al;
7770 
7771 }
7772 
7773 template<typename TSeq>
7774 inline AdjList rgraph_bernoulli2(
7775  epiworld_fast_uint n,
7776  epiworld_double p,
7777  bool directed,
7778  Model<TSeq> & model
7779 ) {
7780 
7781  std::vector< int > source;
7782  std::vector< int > target;
7783 
7784  // Checking the density (how many)
7785  std::binomial_distribution<> d(
7786  n * (n - 1.0) / (directed ? 1.0 : 2.0),
7787  p
7788  );
7789 
7790  // Need to compensate for the possible number of diagonal
7791  // elements sampled. If n * n, then each diag element has
7792  // 1/(n^2) chance of sampling
7793 
7794  epiworld_fast_uint m = d(model.get_rand_endgine());
7795 
7796  source.resize(m);
7797  target.resize(m);
7798 
7799  double n2 = static_cast<double>(n * n);
7800 
7801  int loc,row,col;
7802  for (epiworld_fast_uint i = 0u; i < m; ++i)
7803  {
7804  loc = floor(model.runif() * n2);
7805  col = floor(static_cast<double>(loc)/static_cast<double>(n));
7806  row = loc - row * n;
7807 
7808  // Undirected needs to swap
7809  if (!directed && (col > row))
7810  std::swap(col, row);
7811 
7812  source[i] = row;
7813  target[i] = col;
7814 
7815  }
7816 
7817  AdjList al(source, target, static_cast<int>(n), directed);
7818 
7819  return al;
7820 
7821 }
7822 
7823 inline AdjList rgraph_ring_lattice(
7824  epiworld_fast_uint n,
7825  epiworld_fast_uint k,
7826  bool directed = false
7827 ) {
7828 
7829  if ((n - 1u) < k)
7830  throw std::logic_error("k can be at most n - 1.");
7831 
7832  std::vector< int > source;
7833  std::vector< int > target;
7834 
7835  if (!directed)
7836  if (k > 1u) k = static_cast< size_t >(floor(k / 2.0));
7837 
7838  for (size_t i = 0; i < n; ++i)
7839  {
7840 
7841  for (size_t j = 1u; j <= k; ++j)
7842  {
7843 
7844  // Next neighbor
7845  size_t l = i + j;
7846  if (l >= n) l = l - n;
7847 
7848  source.push_back(i);
7849  target.push_back(l);
7850 
7851  }
7852 
7853  }
7854 
7855  return AdjList(source, target, n, directed);
7856 
7857 }
7858 
7870 template<typename TSeq>
7871 inline AdjList rgraph_smallworld(
7872  epiworld_fast_uint n,
7873  epiworld_fast_uint k,
7874  epiworld_double p,
7875  bool directed,
7876  Model<TSeq> & model
7877 ) {
7878 
7879  // Creating the ring lattice
7880  AdjList ring = rgraph_ring_lattice(n,k,directed);
7881 
7882  // Rewiring and returning
7883  if (k > 0u)
7884  rewire_degseq(&ring, &model, p);
7885 
7886  return ring;
7887 
7888 }
7889 
7903 template<typename TSeq>
7904 inline AdjList rgraph_blocked(
7905  epiworld_fast_uint n,
7906  epiworld_fast_uint blocksize,
7907  epiworld_fast_uint ncons,
7908  Model<TSeq>&
7909 ) {
7910 
7911  std::vector< int > source_;
7912  std::vector< int > target_;
7913 
7914  size_t i = 0u;
7915  size_t cum_node_count = 0u;
7916  while (i < n)
7917  {
7918 
7919  for (size_t j = 0; j < blocksize; ++j)
7920  {
7921 
7922  for (size_t k = 0; k < j; ++k)
7923  {
7924  // No loops
7925  if (k == j)
7926  continue;
7927 
7928  // Exists the loop in case there are no more
7929  // nodes available
7930  if ((i + k) >= n)
7931  break;
7932 
7933  source_.push_back(static_cast<int>(j + i));
7934  target_.push_back(static_cast<int>(k + i));
7935  }
7936 
7937  // No more nodes left to build connections
7938  if (++cum_node_count >= n)
7939  break;
7940 
7941  }
7942 
7943  // Connections between this and the previou sone
7944  if (i != 0)
7945  {
7946 
7947  size_t max_cons = std::min(ncons, n - cum_node_count);
7948 
7949  // Generating the connections
7950  for (size_t j = 0u; j < max_cons; ++j)
7951  {
7952 
7953  source_.push_back(static_cast<int>(i + j - blocksize));
7954  target_.push_back(static_cast<int>(i + j));
7955 
7956  }
7957  }
7958 
7959  i += blocksize;
7960 
7961  }
7962 
7963  return AdjList(source_, target_, n, false);
7964 
7965 }
7966 
7967 #endif
7968 /*//////////////////////////////////////////////////////////////////////////////
7970 
7971  End of -include/epiworld/randgraph.hpp-
7972 
7975 
7976 
7977 
7978 /*//////////////////////////////////////////////////////////////////////////////
7980 
7981  Start of -include/epiworld/queue-bones.hpp-
7982 
7985 
7986 
7987 #ifndef EPIWORLD_QUEUE_BONES_HPP
7988 #define EPIWORLD_QUEUE_BONES_HPP
7989 
8000 template<typename TSeq>
8001 class Queue
8002 {
8003  friend class Model<TSeq>;
8004 
8005 private:
8006 
8010  std::vector< epiworld_fast_int > active;
8011  Model<TSeq> * model = nullptr;
8012  int n_in_queue = 0;
8013 
8014  // Auxiliary variable that checks how many steps
8015  // left are there
8016  // int n_steps_left;
8017  // bool queuing_started = false;
8018 
8019 public:
8020 
8021  void operator+=(Agent<TSeq> * p);
8022  void operator-=(Agent<TSeq> * p);
8023  epiworld_fast_int & operator[](epiworld_fast_uint i);
8024 
8025  // void initialize(Model<TSeq> * m, Agent<TSeq> * p);
8026  void reset();
8027 
8028  bool operator==(const Queue<TSeq> & other) const;
8029  bool operator!=(const Queue<TSeq> & other) const {return !operator==(other);};
8030 
8031  static const int NoOne = 0;
8032  static const int OnlySelf = 1;
8033  static const int Everyone = 2;
8034 
8035 };
8036 
8037 template<typename TSeq>
8038 inline void Queue<TSeq>::operator+=(Agent<TSeq> * p)
8039 {
8040 
8041  if (++active[p->id] == 1)
8042  n_in_queue++;
8043 
8044  if (p->get_n_neighbors() == 0u)
8045  return; // No neighbors, no need to add them
8046 
8047  for (auto n : (*p->neighbors))
8048  {
8049 
8050  if (++active[n] == 1)
8051  n_in_queue++;
8052 
8053  }
8054 
8055 }
8056 
8057 template<typename TSeq>
8058 inline void Queue<TSeq>::operator-=(Agent<TSeq> * p)
8059 {
8060 
8061  if (--active[p->id] == 0)
8062  n_in_queue--;
8063 
8064  if (p->get_n_neighbors() == 0u)
8065  return; // No neighbors, no need to add them
8066 
8067  for (auto n : (*p->neighbors))
8068  {
8069  if (--active[n] == 0)
8070  n_in_queue--;
8071  }
8072 
8073 }
8074 
8075 template<typename TSeq>
8076 inline epiworld_fast_int & Queue<TSeq>::operator[](epiworld_fast_uint i)
8077 {
8078  return active[i];
8079 }
8080 
8081 template<typename TSeq>
8082 inline void Queue<TSeq>::reset()
8083 {
8084 
8085  if (n_in_queue)
8086  {
8087 
8088  for (auto & q : this->active)
8089  q = 0;
8090 
8091  n_in_queue = 0;
8092 
8093  }
8094 
8095  active.resize(model->size(), 0);
8096 
8097 }
8098 
8099 template<typename TSeq>
8100 inline bool Queue<TSeq>::operator==(const Queue<TSeq> & other) const
8101 {
8102  if (active.size() != other.active.size())
8103  return false;
8104 
8105  for (size_t i = 0u; i < active.size(); ++i)
8106  {
8107  if (active[i] != other.active[i])
8108  return false;
8109  }
8110 
8111  return true;
8112 }
8113 
8114 #endif
8115 /*//////////////////////////////////////////////////////////////////////////////
8117 
8118  End of -include/epiworld/queue-bones.hpp-
8119 
8122 
8123 
8124 
8125 /*//////////////////////////////////////////////////////////////////////////////
8127 
8128  Start of -include/epiworld/globalevent-bones.hpp-
8129 
8132 
8133 
8134 #ifndef EPIWORLD_GLOBALEVENT_BONES_HPP
8135 #define EPIWORLD_GLOBALEVENT_BONES_HPP
8136 
8137 // template<typename TSeq = EPI_DEFAULT_TSEQ>
8138 // using GlobalFun = std::function<void(Model<TSeq>*)>;
8139 
8146 template<typename TSeq>
8147 class GlobalEvent
8148 {
8149 private:
8150  GlobalFun<TSeq> fun = nullptr;
8151  std::string name = "A global action";
8152  int day = -99;
8153 public:
8154 
8155  GlobalEvent() {};
8156 
8164  GlobalEvent(GlobalFun<TSeq> fun, std::string name, int day = -99);
8165 
8166  ~GlobalEvent() {};
8167 
8168  void operator()(Model<TSeq> * m, int day);
8169 
8170  void set_name(std::string name);
8171  std::string get_name() const;
8172 
8173  void set_day(int day);
8174  int get_day() const;
8175 
8176  void print() const;
8177 
8178  // Comparison operators
8179  bool operator==(const GlobalEvent<TSeq> & other) const;
8180  bool operator!=(const GlobalEvent<TSeq> & other) const;
8181 
8182 };
8183 
8184 
8185 
8186 #endif
8187 /*//////////////////////////////////////////////////////////////////////////////
8189 
8190  End of -include/epiworld/globalevent-bones.hpp-
8191 
8194 
8195 
8196 /*//////////////////////////////////////////////////////////////////////////////
8198 
8199  Start of -include/epiworld/globalevent-meat.hpp-
8200 
8203 
8204 
8205 #ifndef EPIWORLD_GLOBALEVENT_MEAT_HPP
8206 #define EPIWORLD_GLOBALEVENT_MEAT_HPP
8207 
8208 template<typename TSeq>
8209 inline GlobalEvent<TSeq>::GlobalEvent(
8210  GlobalFun<TSeq> fun,
8211  std::string name,
8212  int day
8213  )
8214 {
8215  this->fun = fun;
8216  this->name = name;
8217  this->day = day;
8218 }
8219 
8220 template<typename TSeq>
8221 inline void GlobalEvent<TSeq>::operator()(Model<TSeq> * m, int day)
8222 {
8223 
8224  if (this->fun == nullptr)
8225  return;
8226 
8227  // events apply if day is negative or if day is equal to the day of the action
8228  if (this->day < 0 || this->day == day)
8229  this->fun(m);
8230 
8231  return;
8232 
8233 }
8234 
8235 template<typename TSeq>
8236 inline void GlobalEvent<TSeq>::set_name(std::string name)
8237 {
8238  this->name = name;
8239 }
8240 
8241 template<typename TSeq>
8242 inline std::string GlobalEvent<TSeq>::get_name() const
8243 {
8244  return this->name;
8245 }
8246 
8247 template<typename TSeq>
8248 inline void GlobalEvent<TSeq>::set_day(int day)
8249 {
8250  this->day = day;
8251 }
8252 
8253 template<typename TSeq>
8254 inline int GlobalEvent<TSeq>::get_day() const
8255 {
8256  return this->day;
8257 }
8258 
8259 template<typename TSeq>
8260 inline void GlobalEvent<TSeq>::print() const
8261 {
8262  printf_epiworld(
8263  "Global action: %s\n"
8264  " - Day: %i\n",
8265  this->name.c_str(),
8266  this->day
8267  );
8268 }
8269 
8270 template<typename TSeq>
8271 inline bool GlobalEvent<TSeq>::operator==(const GlobalEvent<TSeq> & other) const
8272 {
8273  return (this->name == other.name) && (this->day == other.day);
8274 }
8275 
8276 template<typename TSeq>
8277 inline bool GlobalEvent<TSeq>::operator!=(const GlobalEvent<TSeq> & other) const
8278 {
8279  return !(*this == other);
8280 }
8281 
8282 #endif
8283 /*//////////////////////////////////////////////////////////////////////////////
8285 
8286  End of -include/epiworld/globalevent-meat.hpp-
8287 
8290 
8291 
8292 
8293 /*//////////////////////////////////////////////////////////////////////////////
8295 
8296  Start of -include/epiworld/model-bones.hpp-
8297 
8300 
8301 
8302 #ifndef EPIWORLD_MODEL_BONES_HPP
8303 #define EPIWORLD_MODEL_BONES_HPP
8304 
8305 template<typename TSeq>
8306 class Agent;
8307 
8308 template<typename TSeq>
8309 class AgentsSample;
8310 
8311 template<typename TSeq>
8312 class Virus;
8313 
8314 template<typename TSeq>
8315 class Viruses;
8316 
8317 template<typename TSeq>
8318 class Viruses_const;
8319 
8320 template<typename TSeq>
8321 class Tool;
8322 
8323 class AdjList;
8324 
8325 template<typename TSeq>
8326 class DataBase;
8327 
8328 template<typename TSeq>
8329 class Queue;
8330 
8331 template<typename TSeq>
8332 struct Event;
8333 
8334 template<typename TSeq>
8335 class GlobalEvent;
8336 
8337 template<typename TSeq>
8338 inline epiworld_double susceptibility_reduction_mixer_default(
8339  Agent<TSeq>* p,
8340  VirusPtr<TSeq> v,
8341  Model<TSeq>* m
8342  );
8343 template<typename TSeq>
8344 inline epiworld_double transmission_reduction_mixer_default(
8345  Agent<TSeq>* p,
8346  VirusPtr<TSeq> v,
8347  Model<TSeq>* m
8348  );
8349 template<typename TSeq>
8350 inline epiworld_double recovery_enhancer_mixer_default(
8351  Agent<TSeq>* p,
8352  VirusPtr<TSeq> v,
8353  Model<TSeq>* m
8354  );
8355 template<typename TSeq>
8356 inline epiworld_double death_reduction_mixer_default(
8357  Agent<TSeq>* p,
8358  VirusPtr<TSeq> v,
8359  Model<TSeq>* m
8360  );
8361 
8362 template<typename TSeq = EPI_DEFAULT_TSEQ>
8363 inline std::function<void(size_t,Model<TSeq>*)> make_save_run(
8364  std::string fmt = "%03lu-episimulation.csv",
8365  bool total_hist = true,
8366  bool virus_info = false,
8367  bool virus_hist = false,
8368  bool tool_info = false,
8369  bool tool_hist = false,
8370  bool transmission = false,
8371  bool transition = false,
8372  bool reproductive = false,
8373  bool generation = false
8374  );
8375 
8376 // template<typename TSeq>
8377 // class VirusPtr;
8378 
8379 // template<typename TSeq>
8380 // class ToolPtr;
8381 
8391 template<typename TSeq>
8392 class Model {
8393  friend class Agent<TSeq>;
8394  friend class AgentsSample<TSeq>;
8395  friend class DataBase<TSeq>;
8396  friend class Queue<TSeq>;
8397 protected:
8398 
8399  std::string name = ""; ///< Name of the model
8400 
8401  DataBase<TSeq> db = DataBase<TSeq>(*this);
8402 
8403  std::vector< Agent<TSeq> > population = {};
8404 
8405  bool using_backup = true;
8406  std::vector< Agent<TSeq> > population_backup = {};
8407 
8417  std::vector< Agent<TSeq> * > sampled_population;
8418  size_t sampled_population_n = 0u;
8419  std::vector< size_t > population_left;
8420  size_t population_left_n = 0u;
8422 
8432  double * agents_data = nullptr;
8433  size_t agents_data_ncols = 0u;
8435 
8436  bool directed = false;
8437 
8438  std::vector< VirusPtr<TSeq> > viruses = {};
8439  std::vector< ToolPtr<TSeq> > tools = {};
8440 
8441  std::vector< Entity<TSeq> > entities = {};
8442  std::vector< Entity<TSeq> > entities_backup = {};
8443 
8444  std::shared_ptr< std::mt19937 > engine = std::make_shared< std::mt19937 >();
8445 
8446  std::uniform_real_distribution<> runifd =
8447  std::uniform_real_distribution<> (0.0, 1.0);
8448  std::normal_distribution<> rnormd =
8449  std::normal_distribution<>(0.0);
8450  std::gamma_distribution<> rgammad =
8451  std::gamma_distribution<>();
8452  std::lognormal_distribution<> rlognormald =
8453  std::lognormal_distribution<>();
8454  std::exponential_distribution<> rexpd =
8455  std::exponential_distribution<>();
8456  std::binomial_distribution<> rbinomd =
8457  std::binomial_distribution<>();
8458  std::negative_binomial_distribution<> rnbinomd =
8459  std::negative_binomial_distribution<>();
8460  std::geometric_distribution<> rgeomd =
8461  std::geometric_distribution<>();
8462  std::poisson_distribution<> rpoissd =
8463  std::poisson_distribution<>();
8464 
8465  std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> rewire_fun;
8466  epiworld_double rewire_prop = 0.0;
8467 
8468  std::map<std::string, epiworld_double > parameters;
8469  epiworld_fast_uint ndays = 0;
8470  Progress pb;
8471 
8472  std::vector< UpdateFun<TSeq> > state_fun = {}; ///< Functions to update states
8473  std::vector< std::string > states_labels = {}; ///< Labels of the states
8474 
8476  std::function<void(Model<TSeq>*)> initial_states_fun = [](Model<TSeq> * /**/)
8477  -> void {};
8478 
8479  epiworld_fast_uint nstates = 0u;
8480 
8481  bool verbose = true;
8482  int current_date = 0;
8483 
8484  void dist_tools();
8485  void dist_virus();
8486  void dist_entities();
8487 
8488  std::chrono::time_point<std::chrono::steady_clock> time_start;
8489  std::chrono::time_point<std::chrono::steady_clock> time_end;
8490 
8491  // std::chrono::milliseconds
8492  std::chrono::duration<epiworld_double,std::micro> time_elapsed =
8493  std::chrono::duration<epiworld_double,std::micro>::zero();
8494  epiworld_fast_uint n_replicates = 0u;
8495  void chrono_start();
8496  void chrono_end();
8497 
8498  std::vector<GlobalEvent<TSeq>> globalevents;
8499 
8500  Queue<TSeq> queue;
8501  bool use_queuing = true;
8502 
8507  std::vector< Event<TSeq> > events = {};
8508  epiworld_fast_uint nactions = 0u;
8509 
8524  Agent<TSeq> * agent_,
8525  VirusPtr<TSeq> virus_,
8526  ToolPtr<TSeq> tool_,
8527  Entity<TSeq> * entity_,
8528  epiworld_fast_int new_state_,
8529  epiworld_fast_int queue_,
8530  EventFun<TSeq> call_,
8531  int idx_agent_,
8532  int idx_object_
8533  );
8534 
8544  MixerFun<TSeq> susceptibility_reduction_mixer = susceptibility_reduction_mixer_default<TSeq>;
8545  MixerFun<TSeq> transmission_reduction_mixer = transmission_reduction_mixer_default<TSeq>;
8546  MixerFun<TSeq> recovery_enhancer_mixer = recovery_enhancer_mixer_default<TSeq>;
8547  MixerFun<TSeq> death_reduction_mixer = death_reduction_mixer_default<TSeq>;
8548 
8554  virtual Model<TSeq> * clone_ptr();
8555 
8556 public:
8557 
8558 
8559  std::vector<epiworld_double> array_double_tmp;
8560  std::vector<Virus<TSeq> * > array_virus_tmp;
8561 
8562  Model();
8563  Model(const Model<TSeq> & m);
8564  Model(Model<TSeq> & m);
8565  Model(Model<TSeq> && m);
8566  Model<TSeq> & operator=(const Model<TSeq> & m);
8567 
8568  virtual ~Model() {};
8569 
8578  void set_backup();
8579  // void restore_backup();
8581 
8582  DataBase<TSeq> & get_db();
8583  const DataBase<TSeq> & get_db() const;
8584  epiworld_double & operator()(std::string pname);
8585 
8586  size_t size() const;
8587 
8595  void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
8596  std::shared_ptr< std::mt19937 > & get_rand_endgine();
8597  void seed(size_t s);
8598  void set_rand_norm(epiworld_double mean, epiworld_double sd);
8599  void set_rand_unif(epiworld_double a, epiworld_double b);
8600  void set_rand_exp(epiworld_double lambda);
8601  void set_rand_gamma(epiworld_double alpha, epiworld_double beta);
8602  void set_rand_lognormal(epiworld_double mean, epiworld_double shape);
8603  void set_rand_binom(int n, epiworld_double p);
8604  void set_rand_nbinom(int n, epiworld_double p);
8605  void set_rand_geom(epiworld_double p);
8606  void set_rand_poiss(epiworld_double lambda);
8607  epiworld_double runif();
8608  epiworld_double runif(epiworld_double a, epiworld_double b);
8609  epiworld_double rnorm();
8610  epiworld_double rnorm(epiworld_double mean, epiworld_double sd);
8611  epiworld_double rgamma();
8612  epiworld_double rgamma(epiworld_double alpha, epiworld_double beta);
8613  epiworld_double rexp();
8614  epiworld_double rexp(epiworld_double lambda);
8615  epiworld_double rlognormal();
8616  epiworld_double rlognormal(epiworld_double mean, epiworld_double shape);
8617  int rbinom();
8618  int rbinom(int n, epiworld_double p);
8619  int rnbinom();
8620  int rnbinom(int n, epiworld_double p);
8621  int rgeom();
8622  int rgeom(epiworld_double p);
8623  int rpoiss();
8624  int rpoiss(epiworld_double lambda);
8626 
8639  void add_virus(Virus<TSeq> & v);
8640  void add_tool(Tool<TSeq> & t);
8641  void add_entity(Entity<TSeq> e);
8642  void rm_virus(size_t virus_pos);
8643  void rm_tool(size_t tool_pos);
8644  void rm_entity(size_t entity_id);
8646 
8657  void load_agents_entities_ties(std::string fn, int skip);
8658 
8663  const std::vector<int> & agents_ids,
8664  const std::vector<int> & entities_ids
8665  );
8666 
8667  void load_agents_entities_ties(
8668  const int * agents_id,
8669  const int * entities_id,
8670  size_t n
8671  );
8672 
8683  void agents_from_adjlist(
8684  std::string fn,
8685  int size,
8686  int skip = 0,
8687  bool directed = false
8688  );
8689 
8690  void agents_from_edgelist(
8691  const std::vector< int > & source,
8692  const std::vector< int > & target,
8693  int size,
8694  bool directed
8695  );
8696 
8697  void agents_from_adjlist(AdjList al);
8698 
8699  bool is_directed() const;
8700 
8701  std::vector< Agent<TSeq> > & get_agents();
8702 
8703  Agent<TSeq> & get_agent(size_t i);
8704 
8705  std::vector< epiworld_fast_uint > get_agents_states() const;
8706 
8707  std::vector< Viruses_const<TSeq> > get_agents_viruses() const;
8708 
8709  std::vector< Viruses<TSeq> > get_agents_viruses();
8710 
8711  std::vector< Entity<TSeq> > & get_entities();
8712 
8713  Entity<TSeq> & get_entity(size_t entity_id, int * entity_pos = nullptr);
8714 
8715  Model<TSeq> & agents_smallworld(
8716  epiworld_fast_uint n = 1000,
8717  epiworld_fast_uint k = 5,
8718  bool d = false,
8719  epiworld_double p = .01
8720  );
8721  void agents_empty_graph(epiworld_fast_uint n = 1000);
8723 
8734  void update_state();
8735  void mutate_virus();
8736  void next();
8737  virtual Model<TSeq> & run(
8738  epiworld_fast_uint ndays,
8739  int seed = -1
8740  );
8742  epiworld_fast_uint ndays,
8743  epiworld_fast_uint nexperiments,
8744  int seed_ = -1,
8745  std::function<void(size_t,Model<TSeq>*)> fun = make_save_run<TSeq>(),
8746  bool reset = true,
8747  bool verbose = true,
8748  int nthreads = 1
8749  );
8751 
8752  size_t get_n_viruses() const;
8753  size_t get_n_tools() const;
8754  epiworld_fast_uint get_ndays() const;
8755  epiworld_fast_uint get_n_replicates() const;
8756  size_t get_n_entities() const;
8757  void set_ndays(epiworld_fast_uint ndays);
8758  bool get_verbose() const;
8759  Model<TSeq> & verbose_off();
8760  Model<TSeq> & verbose_on();
8761  int today() const;
8762 
8775  void set_rewire_fun(std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> fun);
8776  void set_rewire_prop(epiworld_double prop);
8777  epiworld_double get_rewire_prop() const;
8778  void rewire();
8780 
8794  std::string fn_virus_info,
8795  std::string fn_virus_hist,
8796  std::string fn_tool_info,
8797  std::string fn_tool_hist,
8798  std::string fn_total_hist,
8799  std::string fn_transmission,
8800  std::string fn_transition,
8801  std::string fn_reproductive_number,
8802  std::string fn_generation_time
8803  ) const;
8804 
8816  void write_edgelist(
8817  std::string fn
8818  ) const;
8819 
8820  void write_edgelist(
8821  std::vector< int > & source,
8822  std::vector< int > & target
8823  ) const;
8825 
8826  std::map<std::string, epiworld_double> & params();
8827 
8839  virtual void reset();
8840  const Model<TSeq> & print(bool lite = false) const;
8841 
8857  void add_state(std::string lab, UpdateFun<TSeq> fun = nullptr);
8858  const std::vector< std::string > & get_states() const;
8859  size_t get_n_states() const;
8860  const std::vector< UpdateFun<TSeq> > & get_state_fun() const;
8861  void print_state_codes() const;
8863 
8872  virtual Model<TSeq> & initial_states(
8873  std::vector< double > /*proportions_*/,
8874  std::vector< int > /*queue_*/
8875  ) {return *this;};
8876 
8912  epiworld_double add_param(
8913  epiworld_double initial_val, std::string pname, bool overwrite = false
8914  );
8915  Model<TSeq> & read_params(std::string fn, bool overwrite = false);
8916  epiworld_double get_param(epiworld_fast_uint k);
8917  epiworld_double get_param(std::string pname);
8918  // void set_param(size_t k, epiworld_double val);
8919  void set_param(std::string pname, epiworld_double val);
8920  // epiworld_double par(epiworld_fast_uint k);
8921  epiworld_double par(std::string pname) const;
8923 
8924  void get_elapsed(
8925  std::string unit = "auto",
8926  epiworld_double * last_elapsed = nullptr,
8927  epiworld_double * total_elapsed = nullptr,
8928  std::string * unit_abbr = nullptr,
8929  bool print = true
8930  ) const;
8931 
8938  void set_user_data(std::vector< std::string > names);
8939  void add_user_data(epiworld_fast_uint j, epiworld_double x);
8940  void add_user_data(std::vector< epiworld_double > x);
8941  UserData<TSeq> & get_user_data();
8943 
8956  std::function<void(Model<TSeq>*)> fun,
8957  std::string name = "A global action",
8958  int date = -99
8959  );
8960 
8961  void add_globalevent(
8962  GlobalEvent<TSeq> action
8963  );
8964 
8965  GlobalEvent<TSeq> & get_globalevent(std::string name);
8967 
8968  void rm_globalevent(std::string name);
8969  void rm_globalevent(size_t i);
8970 
8971  void run_globalevents();
8972 
8973  void clear_state_set();
8974 
8983  void queuing_on();
8985  bool is_queuing_on() const;
8988 
8996  void set_susceptibility_reduction_mixer(MixerFun<TSeq> fun);
8997  void set_transmission_reduction_mixer(MixerFun<TSeq> fun);
8998  void set_recovery_enhancer_mixer(MixerFun<TSeq> fun);
8999  void set_death_reduction_mixer(MixerFun<TSeq> fun);
9001 
9002  const std::vector< VirusPtr<TSeq> > & get_viruses() const;
9003  const std::vector< ToolPtr<TSeq> > & get_tools() const;
9004  Virus<TSeq> & get_virus(size_t id);
9005  Tool<TSeq> & get_tool(size_t id);
9006 
9018  void set_agents_data(double * data_, size_t ncols_);
9019  double * get_agents_data();
9020  size_t get_agents_data_ncols() const;
9021 
9027  void set_name(std::string name);
9028  std::string get_name() const;
9029 
9030  bool operator==(const Model<TSeq> & other) const;
9031  bool operator!=(const Model<TSeq> & other) const {return !operator==(other);};
9032 
9038  void events_run();
9039 
9047  void draw(
9048  DiagramType diagram_type = DiagramType::Mermaid,
9049  const std::string & fn_output = "",
9050  bool self = false
9051  );
9052 
9053 
9054 };
9055 
9056 #endif
9057 /*//////////////////////////////////////////////////////////////////////////////
9059 
9060  End of -include/epiworld/model-bones.hpp-
9061 
9064 
9065 
9066 /*//////////////////////////////////////////////////////////////////////////////
9068 
9069  Start of -include/epiworld/model-meat.hpp-
9070 
9073 
9074 
9075 #ifndef EPIWORLD_MODEL_MEAT_HPP
9076 #define EPIWORLD_MODEL_MEAT_HPP
9077 
9078 #include <vector>
9079 #include <functional>
9080 #include <memory>
9081 #include <random>
9082 #include <string>
9083 #include <map>
9084 #include <unordered_map>
9085 /*//////////////////////////////////////////////////////////////////////////////
9087 
9088  Start of -include/epiworld/config.hpp-
9089 
9092 
9093 
9094 #ifndef EPIWORLD_CONFIG_HPP
9095 #define EPIWORLD_CONFIG_HPP
9096 
9097 #ifndef printf_epiworld
9098  #define printf_epiworld fflush(stdout);printf
9099 #endif
9100 
9101 // In case the user has a way to stop the program
9102 // This is called during `run_multiple()` and it is
9103 // passed the simulation number.
9104 #ifndef EPI_CHECK_USER_INTERRUPT
9105  #define EPI_CHECK_USER_INTERRUPT(a)
9106 #endif
9107 
9108 #ifndef EPIWORLD_MAXNEIGHBORS
9109  #define EPIWORLD_MAXNEIGHBORS 1048576
9110 #endif
9111 
9112 #if defined(_OPENMP) || defined(__OPENMP)
9113  #include <omp.h>
9114 // #else
9115 // #define omp_get_thread_num() 0
9116 // #define omp_set_num_threads() 1
9117 #endif
9118 
9119 #ifndef epiworld_double
9120  #define epiworld_double float
9121 #endif
9122 
9123 #ifndef epiworld_fast_int
9124  #define epiworld_fast_int int
9125 #endif
9126 
9127 #ifndef epiworld_fast_uint
9128  #define epiworld_fast_uint unsigned long long int
9129 #endif
9130 
9131 #define EPI_DEFAULT_TSEQ int
9132 
9133 #ifndef EPI_MAX_TRACKING
9134  #define EPI_MAX_TRACKING 200
9135 #endif
9136 
9137 template<typename TSeq = EPI_DEFAULT_TSEQ>
9138 class Model;
9139 
9140 template<typename TSeq = EPI_DEFAULT_TSEQ>
9141 class Agent;
9142 
9143 template<typename TSeq = EPI_DEFAULT_TSEQ>
9144 class PersonTools;
9145 
9146 template<typename TSeq = EPI_DEFAULT_TSEQ>
9147 class Virus;
9148 
9149 template<typename TSeq = EPI_DEFAULT_TSEQ>
9150 class Viruses;
9151 
9152 template<typename TSeq = EPI_DEFAULT_TSEQ>
9153 class Viruses_const;
9154 
9155 template<typename TSeq = EPI_DEFAULT_TSEQ>
9156 class Tool;
9157 
9158 template<typename TSeq = EPI_DEFAULT_TSEQ>
9159 class Tools;
9160 
9161 template<typename TSeq = EPI_DEFAULT_TSEQ>
9162 class Tools_const;
9163 
9164 template<typename TSeq = EPI_DEFAULT_TSEQ>
9165 class Entity;
9166 
9167 template<typename TSeq = EPI_DEFAULT_TSEQ>
9168 using VirusPtr = std::shared_ptr< Virus< TSeq > >;
9169 
9170 template<typename TSeq = EPI_DEFAULT_TSEQ>
9171 using ToolPtr = std::shared_ptr< Tool< TSeq > >;
9172 
9173 template<typename TSeq = EPI_DEFAULT_TSEQ>
9174 using ToolFun = std::function<epiworld_double(Tool<TSeq>&,Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
9175 
9176 template<typename TSeq = EPI_DEFAULT_TSEQ>
9177 using MixerFun = std::function<epiworld_double(Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
9178 
9179 template<typename TSeq = EPI_DEFAULT_TSEQ>
9180 using MutFun = std::function<bool(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
9181 
9182 template<typename TSeq = EPI_DEFAULT_TSEQ>
9183 using PostRecoveryFun = std::function<void(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
9184 
9185 template<typename TSeq = EPI_DEFAULT_TSEQ>
9186 using VirusFun = std::function<epiworld_double(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
9187 
9188 template<typename TSeq = EPI_DEFAULT_TSEQ>
9189 using UpdateFun = std::function<void(Agent<TSeq>*,Model<TSeq>*)>;
9190 
9191 template<typename TSeq = EPI_DEFAULT_TSEQ>
9192 using GlobalFun = std::function<void(Model<TSeq>*)>;
9193 
9194 template<typename TSeq>
9195 struct Event;
9196 
9197 template<typename TSeq = EPI_DEFAULT_TSEQ>
9198 using EventFun = std::function<void(Event<TSeq>&,Model<TSeq>*)>;
9199 
9203 template<typename TSeq = EPI_DEFAULT_TSEQ>
9204 using VirusToAgentFun = std::function<void(Virus<TSeq>&,Model<TSeq>*)>;
9205 
9209 template<typename TSeq = EPI_DEFAULT_TSEQ>
9210 using ToolToAgentFun = std::function<void(Tool<TSeq>&,Model<TSeq>*)>;
9211 
9215 template<typename TSeq = EPI_DEFAULT_TSEQ>
9216 using EntityToAgentFun = std::function<void(Entity<TSeq>&,Model<TSeq>*)>;
9217 
9223 template<typename TSeq = EPI_DEFAULT_TSEQ>
9224 struct Event {
9225  Agent<TSeq> * agent;
9226  VirusPtr<TSeq> virus;
9227  ToolPtr<TSeq> tool;
9228  Entity<TSeq> * entity;
9229  epiworld_fast_int new_state;
9230  epiworld_fast_int queue;
9231  EventFun<TSeq> call;
9232  int idx_agent;
9233  int idx_object;
9234 public:
9251  Event(
9252  Agent<TSeq> * agent_,
9253  VirusPtr<TSeq> & virus_,
9254  ToolPtr<TSeq> & tool_,
9255  Entity<TSeq> * entity_,
9256  epiworld_fast_int new_state_,
9257  epiworld_fast_int queue_,
9258  EventFun<TSeq> & call_,
9259  int idx_agent_,
9260  int idx_object_
9261  ) : agent(agent_), virus(virus_), tool(tool_), entity(entity_),
9262  new_state(new_state_),
9263  queue(queue_), call(call_), idx_agent(idx_agent_), idx_object(idx_object_) {
9264  return;
9265  };
9266 };
9267 
9275 #ifndef DEFAULT_TOOL_CONTAGION_REDUCTION
9276  #define DEFAULT_TOOL_CONTAGION_REDUCTION 0.0
9277 #endif
9278 
9279 #ifndef DEFAULT_TOOL_TRANSMISSION_REDUCTION
9280  #define DEFAULT_TOOL_TRANSMISSION_REDUCTION 0.0
9281 #endif
9282 
9283 #ifndef DEFAULT_TOOL_RECOVERY_ENHANCER
9284  #define DEFAULT_TOOL_RECOVERY_ENHANCER 0.0
9285 #endif
9286 
9287 #ifndef DEFAULT_TOOL_DEATH_REDUCTION
9288  #define DEFAULT_TOOL_DEATH_REDUCTION 0.0
9289 #endif
9290 
9291 #ifndef EPI_DEFAULT_VIRUS_PROB_INFECTION
9292  #define EPI_DEFAULT_VIRUS_PROB_INFECTION 1.0
9293 #endif
9294 
9295 #ifndef EPI_DEFAULT_VIRUS_PROB_RECOVERY
9296  #define EPI_DEFAULT_VIRUS_PROB_RECOVERY 0.1428
9297 #endif
9298 
9299 #ifndef EPI_DEFAULT_VIRUS_PROB_DEATH
9300  #define EPI_DEFAULT_VIRUS_PROB_DEATH 0.0
9301 #endif
9302 
9303 #ifndef EPI_DEFAULT_INCUBATION_DAYS
9304  #define EPI_DEFAULT_INCUBATION_DAYS 7.0
9305 #endif
9307 
9308 #ifdef EPI_DEBUG
9309  #define EPI_DEBUG_PRINTF printf_epiworld
9310 
9311  #define EPI_DEBUG_ERROR(etype, msg) \
9312  (etype)("[[epi-debug]] (error) " + std::string(msg));
9313 
9314  #define EPI_DEBUG_NOTIFY_ACTIVE() \
9315  EPI_DEBUG_PRINTF("DEBUGGING ON (compiled with EPI_DEBUG defined)%s\n", "");
9316 
9317  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect) \
9318  for (auto & v : vect) \
9319  if (static_cast<double>(v) < 0.0) \
9320  throw EPI_DEBUG_ERROR(std::logic_error, "A negative value not allowed.");
9321 
9322  #define EPI_DEBUG_SUM_DBL(vect, num) \
9323  double _epi_debug_sum = 0.0; \
9324  for (auto & v : vect) \
9325  { \
9326  _epi_debug_sum += static_cast<double>(v);\
9327  if (_epi_debug_sum > static_cast<double>(num)) \
9328  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
9329  }
9330 
9331  #define EPI_DEBUG_SUM_INT(vect, num) \
9332  int _epi_debug_sum = 0; \
9333  for (auto & v : vect) \
9334  { \
9335  _epi_debug_sum += static_cast<int>(v);\
9336  if (_epi_debug_sum > static_cast<int>(num)) \
9337  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
9338  }
9339 
9340  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c) \
9341  if (a.size() != b.size()) {\
9342  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
9343  EPI_DEBUG_PRINTF("Size of vector a: %lu\n", (a).size());\
9344  EPI_DEBUG_PRINTF("Size of vector b: %lu\n", (b).size());\
9345  throw EPI_DEBUG_ERROR(std::length_error, "The vectors do not match size."); \
9346  }\
9347  for (int _i = 0; _i < static_cast<int>(a.size()); ++_i) \
9348  if (a[_i] != b[_i]) {\
9349  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
9350  EPI_DEBUG_PRINTF("Iterating the last 5 values%s:\n", ""); \
9351  for (int _j = std::max(0, static_cast<int>(_i) - 4); _j <= _i; ++_j) \
9352  { \
9353  EPI_DEBUG_PRINTF( \
9354  "a[%i]: %i; b[%i]: %i\n", \
9355  _j, \
9356  static_cast<int>(a[_j]), \
9357  _j, static_cast<int>(b[_j])); \
9358  } \
9359  throw EPI_DEBUG_ERROR(std::logic_error, "The vectors do not match."); \
9360  }
9361 
9362  #define EPI_DEBUG_FAIL_AT_TRUE(a,b) \
9363  if (a) \
9364  {\
9365  throw EPI_DEBUG_ERROR(std::logic_error, b); \
9366  }
9367 
9368  #define epiexception(a) std::logic_error
9369 #else
9370  #define EPI_DEBUG_PRINTF(fmt, ...)
9371  #define EPI_DEBUG_ERROR(fmt, ...)
9372  #define EPI_DEBUG_NOTIFY_ACTIVE()
9373  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect)
9374  #define EPI_DEBUG_SUM_DBL(vect, num)
9375  #define EPI_DEBUG_SUM_INT(vect, num)
9376  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c)
9377  #define EPI_DEBUG_FAIL_AT_TRUE(a, b) \
9378  if (a) \
9379  return false;
9380  #define epiexception(a) a
9381 #endif
9382 
9383 #if defined(EPI_DEBUG_NO_THREAD_ID) || (!defined(__OPENMP) && !defined(_OPENMP))
9384  #define EPI_GET_THREAD_ID() 0
9385 #else
9386  #define EPI_GET_THREAD_ID() omp_get_thread_num()
9387 #endif
9388 
9389 #endif
9390 /*//////////////////////////////////////////////////////////////////////////////
9392 
9393  End of -include/epiworld/config.hpp-
9394 
9397 
9398 
9399 /*//////////////////////////////////////////////////////////////////////////////
9401 
9402  Start of -include/epiworld/userdata-bones.hpp-
9403 
9406 
9407 
9408 #ifndef EPIWORLD_USERDATA_BONES_HPP
9409 #define EPIWORLD_USERDATA_BONES_HPP
9410 
9411 template<typename TSeq>
9412 class Model;
9413 
9414 template<typename TSeq>
9415 class DataBase;
9416 
9422 template<typename TSeq>
9423 class UserData
9424 {
9425  friend class Model<TSeq>;
9426  friend class DataBase<TSeq>;
9427 
9428 private:
9429  Model<TSeq> * model;
9430 
9431  std::vector< std::string > data_names;
9432  std::vector< int > data_dates;
9433  std::vector< epiworld_double > data_data;
9434 
9435  epiworld_fast_uint k = 0u;
9436  epiworld_fast_uint n = 0u;
9437 
9438  int last_day = -1;
9439 
9440 public:
9441 
9442  UserData() = delete;
9443  UserData(Model<TSeq> & m) : model(&m) {};
9444  UserData(Model<TSeq> * m) : model(m) {};
9445 
9452  UserData(std::vector< std::string > names);
9453 
9461  void add(std::vector<epiworld_double> x);
9462  void add(
9463  epiworld_fast_uint j,
9464  epiworld_double x
9465  );
9467 
9476  epiworld_double & operator()(
9477  epiworld_fast_uint i,
9478  epiworld_fast_uint j
9479  );
9480 
9481  epiworld_double & operator()(
9482  epiworld_fast_uint i,
9483  std::string name
9484  );
9486 
9487  std::vector< std::string > & get_names();
9488 
9489  std::vector< int > & get_dates();
9490 
9491  std::vector< epiworld_double > & get_data();
9492 
9493  void get_all(
9494  std::vector< std::string > * names = nullptr,
9495  std::vector< int > * date = nullptr,
9496  std::vector< epiworld_double > * data = nullptr
9497  );
9498 
9499  epiworld_fast_uint nrow() const;
9500  epiworld_fast_uint ncol() const;
9501 
9502  void write(std::string fn);
9503  void print() const;
9504 
9505 };
9506 
9507 #endif
9508 /*//////////////////////////////////////////////////////////////////////////////
9510 
9511  End of -include/epiworld/userdata-bones.hpp-
9512 
9515 
9516 
9517 /*//////////////////////////////////////////////////////////////////////////////
9519 
9520  Start of -include/epiworld/adjlist-bones.hpp-
9521 
9524 
9525 
9526 #ifndef EPIWORLD_ADJLIST_BONES_HPP
9527 #define EPIWORLD_ADJLIST_BONES_HPP
9528 
9529 class AdjList {
9530 private:
9531 
9532  std::vector<std::map<int, int>> dat;
9533  bool directed;
9534  epiworld_fast_uint N = 0;
9535  epiworld_fast_uint E = 0;
9536 
9537 public:
9538 
9539  AdjList() {};
9540 
9552  AdjList(
9553  const std::vector< int > & source,
9554  const std::vector< int > & target,
9555  int size,
9556  bool directed
9557  );
9558 
9559  AdjList(AdjList && a); // Move constructor
9560  AdjList(const AdjList & a); // Copy constructor
9561  AdjList& operator=(const AdjList& a);
9562 
9563 
9574  void read_edgelist(
9575  std::string fn,
9576  int size,
9577  int skip = 0,
9578  bool directed = true
9579  );
9580 
9581  std::map<int, int> operator()(
9582  epiworld_fast_uint i
9583  ) const;
9584 
9585  void print(epiworld_fast_uint limit = 20u) const;
9586  size_t vcount() const; ///< Number of vertices/nodes in the network.
9587  size_t ecount() const; ///< Number of edges/arcs/ties in the network.
9588 
9589  std::vector<std::map<int,int>> & get_dat() {
9590  return dat;
9591  };
9592 
9593  bool is_directed() const; ///< `true` if the network is directed.
9594 
9595 };
9596 
9597 
9598 #endif
9599 
9600 /*//////////////////////////////////////////////////////////////////////////////
9602 
9603  End of -include/epiworld/adjlist-bones.hpp-
9604 
9607 
9608 
9609 /*//////////////////////////////////////////////////////////////////////////////
9611 
9612  Start of -include/epiworld/model-bones.hpp-
9613 
9616 
9617 
9618 #ifndef EPIWORLD_MODEL_BONES_HPP
9619 #define EPIWORLD_MODEL_BONES_HPP
9620 
9621 template<typename TSeq>
9622 class Agent;
9623 
9624 template<typename TSeq>
9625 class AgentsSample;
9626 
9627 template<typename TSeq>
9628 class Virus;
9629 
9630 template<typename TSeq>
9631 class Viruses;
9632 
9633 template<typename TSeq>
9634 class Viruses_const;
9635 
9636 template<typename TSeq>
9637 class Tool;
9638 
9639 class AdjList;
9640 
9641 template<typename TSeq>
9642 class DataBase;
9643 
9644 template<typename TSeq>
9645 class Queue;
9646 
9647 template<typename TSeq>
9648 struct Event;
9649 
9650 template<typename TSeq>
9651 class GlobalEvent;
9652 
9653 template<typename TSeq>
9654 inline epiworld_double susceptibility_reduction_mixer_default(
9655  Agent<TSeq>* p,
9656  VirusPtr<TSeq> v,
9657  Model<TSeq>* m
9658  );
9659 template<typename TSeq>
9660 inline epiworld_double transmission_reduction_mixer_default(
9661  Agent<TSeq>* p,
9662  VirusPtr<TSeq> v,
9663  Model<TSeq>* m
9664  );
9665 template<typename TSeq>
9666 inline epiworld_double recovery_enhancer_mixer_default(
9667  Agent<TSeq>* p,
9668  VirusPtr<TSeq> v,
9669  Model<TSeq>* m
9670  );
9671 template<typename TSeq>
9672 inline epiworld_double death_reduction_mixer_default(
9673  Agent<TSeq>* p,
9674  VirusPtr<TSeq> v,
9675  Model<TSeq>* m
9676  );
9677 
9678 template<typename TSeq = EPI_DEFAULT_TSEQ>
9679 inline std::function<void(size_t,Model<TSeq>*)> make_save_run(
9680  std::string fmt = "%03lu-episimulation.csv",
9681  bool total_hist = true,
9682  bool virus_info = false,
9683  bool virus_hist = false,
9684  bool tool_info = false,
9685  bool tool_hist = false,
9686  bool transmission = false,
9687  bool transition = false,
9688  bool reproductive = false,
9689  bool generation = false
9690  );
9691 
9692 // template<typename TSeq>
9693 // class VirusPtr;
9694 
9695 // template<typename TSeq>
9696 // class ToolPtr;
9697 
9707 template<typename TSeq>
9708 class Model {
9709  friend class Agent<TSeq>;
9710  friend class AgentsSample<TSeq>;
9711  friend class DataBase<TSeq>;
9712  friend class Queue<TSeq>;
9713 protected:
9714 
9715  std::string name = ""; ///< Name of the model
9716 
9717  DataBase<TSeq> db = DataBase<TSeq>(*this);
9718 
9719  std::vector< Agent<TSeq> > population = {};
9720 
9721  bool using_backup = true;
9722  std::vector< Agent<TSeq> > population_backup = {};
9723 
9733  std::vector< Agent<TSeq> * > sampled_population;
9734  size_t sampled_population_n = 0u;
9735  std::vector< size_t > population_left;
9736  size_t population_left_n = 0u;
9738 
9748  double * agents_data = nullptr;
9749  size_t agents_data_ncols = 0u;
9751 
9752  bool directed = false;
9753 
9754  std::vector< VirusPtr<TSeq> > viruses = {};
9755  std::vector< ToolPtr<TSeq> > tools = {};
9756 
9757  std::vector< Entity<TSeq> > entities = {};
9758  std::vector< Entity<TSeq> > entities_backup = {};
9759 
9760  std::shared_ptr< std::mt19937 > engine = std::make_shared< std::mt19937 >();
9761 
9762  std::uniform_real_distribution<> runifd =
9763  std::uniform_real_distribution<> (0.0, 1.0);
9764  std::normal_distribution<> rnormd =
9765  std::normal_distribution<>(0.0);
9766  std::gamma_distribution<> rgammad =
9767  std::gamma_distribution<>();
9768  std::lognormal_distribution<> rlognormald =
9769  std::lognormal_distribution<>();
9770  std::exponential_distribution<> rexpd =
9771  std::exponential_distribution<>();
9772  std::binomial_distribution<> rbinomd =
9773  std::binomial_distribution<>();
9774  std::negative_binomial_distribution<> rnbinomd =
9775  std::negative_binomial_distribution<>();
9776  std::geometric_distribution<> rgeomd =
9777  std::geometric_distribution<>();
9778  std::poisson_distribution<> rpoissd =
9779  std::poisson_distribution<>();
9780 
9781  std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> rewire_fun;
9782  epiworld_double rewire_prop = 0.0;
9783 
9784  std::map<std::string, epiworld_double > parameters;
9785  epiworld_fast_uint ndays = 0;
9786  Progress pb;
9787 
9788  std::vector< UpdateFun<TSeq> > state_fun = {}; ///< Functions to update states
9789  std::vector< std::string > states_labels = {}; ///< Labels of the states
9790 
9792  std::function<void(Model<TSeq>*)> initial_states_fun = [](Model<TSeq> * /**/)
9793  -> void {};
9794 
9795  epiworld_fast_uint nstates = 0u;
9796 
9797  bool verbose = true;
9798  int current_date = 0;
9799 
9800  void dist_tools();
9801  void dist_virus();
9802  void dist_entities();
9803 
9804  std::chrono::time_point<std::chrono::steady_clock> time_start;
9805  std::chrono::time_point<std::chrono::steady_clock> time_end;
9806 
9807  // std::chrono::milliseconds
9808  std::chrono::duration<epiworld_double,std::micro> time_elapsed =
9809  std::chrono::duration<epiworld_double,std::micro>::zero();
9810  epiworld_fast_uint n_replicates = 0u;
9811  void chrono_start();
9812  void chrono_end();
9813 
9814  std::vector<GlobalEvent<TSeq>> globalevents;
9815 
9816  Queue<TSeq> queue;
9817  bool use_queuing = true;
9818 
9823  std::vector< Event<TSeq> > events = {};
9824  epiworld_fast_uint nactions = 0u;
9825 
9839  void events_add(
9840  Agent<TSeq> * agent_,
9841  VirusPtr<TSeq> virus_,
9842  ToolPtr<TSeq> tool_,
9843  Entity<TSeq> * entity_,
9844  epiworld_fast_int new_state_,
9845  epiworld_fast_int queue_,
9846  EventFun<TSeq> call_,
9847  int idx_agent_,
9848  int idx_object_
9849  );
9850 
9860  MixerFun<TSeq> susceptibility_reduction_mixer = susceptibility_reduction_mixer_default<TSeq>;
9861  MixerFun<TSeq> transmission_reduction_mixer = transmission_reduction_mixer_default<TSeq>;
9862  MixerFun<TSeq> recovery_enhancer_mixer = recovery_enhancer_mixer_default<TSeq>;
9863  MixerFun<TSeq> death_reduction_mixer = death_reduction_mixer_default<TSeq>;
9864 
9870  virtual Model<TSeq> * clone_ptr();
9871 
9872 public:
9873 
9874 
9875  std::vector<epiworld_double> array_double_tmp;
9876  std::vector<Virus<TSeq> * > array_virus_tmp;
9877 
9878  Model();
9879  Model(const Model<TSeq> & m);
9880  Model(Model<TSeq> & m);
9881  Model(Model<TSeq> && m);
9882  Model<TSeq> & operator=(const Model<TSeq> & m);
9883 
9884  virtual ~Model() {};
9885 
9894  void set_backup();
9895  // void restore_backup();
9897 
9898  DataBase<TSeq> & get_db();
9899  const DataBase<TSeq> & get_db() const;
9900  epiworld_double & operator()(std::string pname);
9901 
9902  size_t size() const;
9903 
9911  void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
9912  std::shared_ptr< std::mt19937 > & get_rand_endgine();
9913  void seed(size_t s);
9914  void set_rand_norm(epiworld_double mean, epiworld_double sd);
9915  void set_rand_unif(epiworld_double a, epiworld_double b);
9916  void set_rand_exp(epiworld_double lambda);
9917  void set_rand_gamma(epiworld_double alpha, epiworld_double beta);
9918  void set_rand_lognormal(epiworld_double mean, epiworld_double shape);
9919  void set_rand_binom(int n, epiworld_double p);
9920  void set_rand_nbinom(int n, epiworld_double p);
9921  void set_rand_geom(epiworld_double p);
9922  void set_rand_poiss(epiworld_double lambda);
9923  epiworld_double runif();
9924  epiworld_double runif(epiworld_double a, epiworld_double b);
9925  epiworld_double rnorm();
9926  epiworld_double rnorm(epiworld_double mean, epiworld_double sd);
9927  epiworld_double rgamma();
9928  epiworld_double rgamma(epiworld_double alpha, epiworld_double beta);
9929  epiworld_double rexp();
9930  epiworld_double rexp(epiworld_double lambda);
9931  epiworld_double rlognormal();
9932  epiworld_double rlognormal(epiworld_double mean, epiworld_double shape);
9933  int rbinom();
9934  int rbinom(int n, epiworld_double p);
9935  int rnbinom();
9936  int rnbinom(int n, epiworld_double p);
9937  int rgeom();
9938  int rgeom(epiworld_double p);
9939  int rpoiss();
9940  int rpoiss(epiworld_double lambda);
9942 
9955  void add_virus(Virus<TSeq> & v);
9956  void add_tool(Tool<TSeq> & t);
9957  void add_entity(Entity<TSeq> e);
9958  void rm_virus(size_t virus_pos);
9959  void rm_tool(size_t tool_pos);
9960  void rm_entity(size_t entity_id);
9962 
9973  void load_agents_entities_ties(std::string fn, int skip);
9974 
9978  void load_agents_entities_ties(
9979  const std::vector<int> & agents_ids,
9980  const std::vector<int> & entities_ids
9981  );
9982 
9983  void load_agents_entities_ties(
9984  const int * agents_id,
9985  const int * entities_id,
9986  size_t n
9987  );
9988 
9999  void agents_from_adjlist(
10000  std::string fn,
10001  int size,
10002  int skip = 0,
10003  bool directed = false
10004  );
10005 
10006  void agents_from_edgelist(
10007  const std::vector< int > & source,
10008  const std::vector< int > & target,
10009  int size,
10010  bool directed
10011  );
10012 
10013  void agents_from_adjlist(AdjList al);
10014 
10015  bool is_directed() const;
10016 
10017  std::vector< Agent<TSeq> > & get_agents();
10018 
10019  Agent<TSeq> & get_agent(size_t i);
10020 
10021  std::vector< epiworld_fast_uint > get_agents_states() const;
10022 
10023  std::vector< Viruses_const<TSeq> > get_agents_viruses() const;
10024 
10025  std::vector< Viruses<TSeq> > get_agents_viruses();
10026 
10027  std::vector< Entity<TSeq> > & get_entities();
10028 
10029  Entity<TSeq> & get_entity(size_t entity_id, int * entity_pos = nullptr);
10030 
10031  Model<TSeq> & agents_smallworld(
10032  epiworld_fast_uint n = 1000,
10033  epiworld_fast_uint k = 5,
10034  bool d = false,
10035  epiworld_double p = .01
10036  );
10037  void agents_empty_graph(epiworld_fast_uint n = 1000);
10039 
10050  void update_state();
10051  void mutate_virus();
10052  void next();
10053  virtual Model<TSeq> & run(
10054  epiworld_fast_uint ndays,
10055  int seed = -1
10056  );
10057  void run_multiple(
10058  epiworld_fast_uint ndays,
10059  epiworld_fast_uint nexperiments,
10060  int seed_ = -1,
10061  std::function<void(size_t,Model<TSeq>*)> fun = make_save_run<TSeq>(),
10062  bool reset = true,
10063  bool verbose = true,
10064  int nthreads = 1
10065  );
10067 
10068  size_t get_n_viruses() const;
10069  size_t get_n_tools() const;
10070  epiworld_fast_uint get_ndays() const;
10071  epiworld_fast_uint get_n_replicates() const;
10072  size_t get_n_entities() const;
10073  void set_ndays(epiworld_fast_uint ndays);
10074  bool get_verbose() const;
10075  Model<TSeq> & verbose_off();
10076  Model<TSeq> & verbose_on();
10077  int today() const;
10078 
10091  void set_rewire_fun(std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> fun);
10092  void set_rewire_prop(epiworld_double prop);
10093  epiworld_double get_rewire_prop() const;
10094  void rewire();
10096 
10109  void write_data(
10110  std::string fn_virus_info,
10111  std::string fn_virus_hist,
10112  std::string fn_tool_info,
10113  std::string fn_tool_hist,
10114  std::string fn_total_hist,
10115  std::string fn_transmission,
10116  std::string fn_transition,
10117  std::string fn_reproductive_number,
10118  std::string fn_generation_time
10119  ) const;
10120 
10132  void write_edgelist(
10133  std::string fn
10134  ) const;
10135 
10136  void write_edgelist(
10137  std::vector< int > & source,
10138  std::vector< int > & target
10139  ) const;
10141 
10142  std::map<std::string, epiworld_double> & params();
10143 
10155  virtual void reset();
10156  const Model<TSeq> & print(bool lite = false) const;
10157 
10173  void add_state(std::string lab, UpdateFun<TSeq> fun = nullptr);
10174  const std::vector< std::string > & get_states() const;
10175  size_t get_n_states() const;
10176  const std::vector< UpdateFun<TSeq> > & get_state_fun() const;
10177  void print_state_codes() const;
10179 
10188  virtual Model<TSeq> & initial_states(
10189  std::vector< double > /*proportions_*/,
10190  std::vector< int > /*queue_*/
10191  ) {return *this;};
10192 
10228  epiworld_double add_param(
10229  epiworld_double initial_val, std::string pname, bool overwrite = false
10230  );
10231  Model<TSeq> & read_params(std::string fn, bool overwrite = false);
10232  epiworld_double get_param(epiworld_fast_uint k);
10233  epiworld_double get_param(std::string pname);
10234  // void set_param(size_t k, epiworld_double val);
10235  void set_param(std::string pname, epiworld_double val);
10236  // epiworld_double par(epiworld_fast_uint k);
10237  epiworld_double par(std::string pname) const;
10239 
10240  void get_elapsed(
10241  std::string unit = "auto",
10242  epiworld_double * last_elapsed = nullptr,
10243  epiworld_double * total_elapsed = nullptr,
10244  std::string * unit_abbr = nullptr,
10245  bool print = true
10246  ) const;
10247 
10254  void set_user_data(std::vector< std::string > names);
10255  void add_user_data(epiworld_fast_uint j, epiworld_double x);
10256  void add_user_data(std::vector< epiworld_double > x);
10257  UserData<TSeq> & get_user_data();
10259 
10271  void add_globalevent(
10272  std::function<void(Model<TSeq>*)> fun,
10273  std::string name = "A global action",
10274  int date = -99
10275  );
10276 
10277  void add_globalevent(
10278  GlobalEvent<TSeq> action
10279  );
10280 
10281  GlobalEvent<TSeq> & get_globalevent(std::string name);
10282  GlobalEvent<TSeq> & get_globalevent(size_t i);
10283 
10284  void rm_globalevent(std::string name);
10285  void rm_globalevent(size_t i);
10286 
10287  void run_globalevents();
10288 
10289  void clear_state_set();
10290 
10299  void queuing_on();
10300  Model<TSeq> & queuing_off();
10301  bool is_queuing_on() const;
10302  Queue<TSeq> & get_queue();
10304 
10312  void set_susceptibility_reduction_mixer(MixerFun<TSeq> fun);
10313  void set_transmission_reduction_mixer(MixerFun<TSeq> fun);
10314  void set_recovery_enhancer_mixer(MixerFun<TSeq> fun);
10315  void set_death_reduction_mixer(MixerFun<TSeq> fun);
10317 
10318  const std::vector< VirusPtr<TSeq> > & get_viruses() const;
10319  const std::vector< ToolPtr<TSeq> > & get_tools() const;
10320  Virus<TSeq> & get_virus(size_t id);
10321  Tool<TSeq> & get_tool(size_t id);
10322 
10334  void set_agents_data(double * data_, size_t ncols_);
10335  double * get_agents_data();
10336  size_t get_agents_data_ncols() const;
10337 
10343  void set_name(std::string name);
10344  std::string get_name() const;
10345 
10346  bool operator==(const Model<TSeq> & other) const;
10347  bool operator!=(const Model<TSeq> & other) const {return !operator==(other);};
10348 
10354  void events_run();
10355 
10363  void draw(
10364  DiagramType diagram_type = DiagramType::Mermaid,
10365  const std::string & fn_output = "",
10366  bool self = false
10367  );
10368 
10369 
10370 };
10371 
10372 #endif
10373 /*//////////////////////////////////////////////////////////////////////////////
10375 
10376  End of -include/epiworld/model-bones.hpp-
10377 
10380 
10381 
10382 /*//////////////////////////////////////////////////////////////////////////////
10384 
10385  Start of -include/epiworld/entities-bones.hpp-
10386 
10389 
10390 
10391 #ifndef EPIWORLD_ENTITIES_BONES_HPP
10392 #define EPIWORLD_ENTITIES_BONES_HPP
10393 
10394 template<typename TSeq>
10395 class Virus;
10396 
10397 template<typename TSeq>
10398 class Agent;
10399 
10400 
10406 template<typename TSeq>
10407 class Entities {
10408  friend class Entity<TSeq>;
10409  friend class Agent<TSeq>;
10410 private:
10411  std::vector< Entity<TSeq> * > dat;
10412  const size_t n_entities;
10413 
10414 public:
10415 
10416  Entities() = delete;
10417  Entities(Agent<TSeq> & p);
10418 
10419  typename std::vector< Entity<TSeq> * >::iterator begin();
10420  typename std::vector< Entity<TSeq> * >::iterator end();
10421 
10422  Entity<TSeq> & operator()(size_t i);
10423  Entity<TSeq> & operator[](size_t i);
10424 
10425  size_t size() const noexcept;
10426 
10427  bool operator==(const Entities<TSeq> & other) const;
10428 
10429 };
10430 
10431 template<typename TSeq>
10432 inline Entities<TSeq>::Entities(Agent<TSeq> & p) :
10433  n_entities(p.get_n_entities())
10434 {
10435 
10436  dat.reserve(n_entities);
10437  for (size_t i = 0u; i < n_entities; ++i)
10438  dat.push_back(&p.get_entity(i));
10439 
10440 }
10441 
10442 template<typename TSeq>
10443 inline typename std::vector< Entity<TSeq>* >::iterator Entities<TSeq>::begin()
10444 {
10445 
10446  if (n_entities == 0u)
10447  return dat.end();
10448 
10449  return dat.begin();
10450 }
10451 
10452 template<typename TSeq>
10453 inline typename std::vector< Entity<TSeq>* >::iterator Entities<TSeq>::end()
10454 {
10455 
10456  return begin() + n_entities;
10457 }
10458 
10459 template<typename TSeq>
10460 inline Entity<TSeq> & Entities<TSeq>::operator()(size_t i)
10461 {
10462 
10463  if (i >= n_entities)
10464  throw std::range_error("Entity index out of range.");
10465 
10466  return *dat[i];
10467 
10468 }
10469 
10470 template<typename TSeq>
10471 inline Entity<TSeq> & Entities<TSeq>::operator[](size_t i)
10472 {
10473 
10474  return *dat[i];
10475 
10476 }
10477 
10478 template<typename TSeq>
10479 inline size_t Entities<TSeq>::size() const noexcept
10480 {
10481  return n_entities;
10482 }
10483 
10484 template<typename TSeq>
10485 inline bool Entities<TSeq>::operator==(const Entities<TSeq> & other) const
10486 {
10487 
10488  if (n_entities != other.n_entities)
10489  return false;
10490 
10491  for (size_t i = 0u; i < dat.size(); ++i)
10492  {
10493  if (dat[i] != other.dat[i])
10494  return false;
10495  }
10496 
10497  return true;
10498 }
10499 
10505 template<typename TSeq>
10506 class Entities_const {
10507  friend class Virus<TSeq>;
10508  friend class Agent<TSeq>;
10509 private:
10510  const std::vector< Entity<TSeq>* > dat;
10511  const size_t n_entities;
10512 
10513 public:
10514 
10515  Entities_const() = delete;
10516  Entities_const(const Agent<TSeq> & p);
10517 
10518  typename std::vector< Entity<TSeq>* >::const_iterator begin();
10519  typename std::vector< Entity<TSeq>* >::const_iterator end();
10520 
10521  const Entity<TSeq> & operator()(size_t i);
10522  const Entity<TSeq> & operator[](size_t i);
10523 
10524  size_t size() const noexcept;
10525 
10526  bool operator==(const Entities_const<TSeq> & other) const;
10527 
10528 };
10529 
10530 template<typename TSeq>
10531 inline Entities_const<TSeq>::Entities_const(const Agent<TSeq> & p) :
10532  n_entities(p.get_n_entities())
10533 {
10534 
10535  dat.reserve(n_entities);
10536  for (size_t i = 0u; i < n_entities; ++i)
10537  dat.push_back(&p.get_entity(i));
10538 
10539 }
10540 
10541 template<typename TSeq>
10542 inline typename std::vector< Entity<TSeq>* >::const_iterator Entities_const<TSeq>::begin() {
10543 
10544  if (n_entities == 0u)
10545  return dat.end();
10546 
10547  return dat.begin();
10548 }
10549 
10550 template<typename TSeq>
10551 inline typename std::vector< Entity<TSeq>* >::const_iterator Entities_const<TSeq>::end() {
10552 
10553  return begin() + n_entities;
10554 }
10555 
10556 template<typename TSeq>
10557 inline const Entity<TSeq> & Entities_const<TSeq>::operator()(size_t i)
10558 {
10559 
10560  if (i >= n_entities)
10561  throw std::range_error("Entity index out of range.");
10562 
10563  return *dat[i];
10564 
10565 }
10566 
10567 template<typename TSeq>
10568 inline const Entity<TSeq> & Entities_const<TSeq>::operator[](size_t i)
10569 {
10570 
10571  return *dat[i];
10572 
10573 }
10574 
10575 template<typename TSeq>
10576 inline size_t Entities_const<TSeq>::size() const noexcept
10577 {
10578  return n_entities;
10579 }
10580 
10581 template<typename TSeq>
10582 inline bool Entities_const<TSeq>::operator==(const Entities_const<TSeq> & other) const
10583 {
10584 
10585  if (n_entities != other.n_entities)
10586  return false;
10587 
10588  for (size_t i = 0u; i < dat.size(); ++i)
10589  {
10590  if (dat[i] != other.dat[i])
10591  return false;
10592  }
10593 
10594  return true;
10595 }
10596 
10597 
10598 #endif
10599 /*//////////////////////////////////////////////////////////////////////////////
10601 
10602  End of -include/epiworld/entities-bones.hpp-
10603 
10606 
10607 
10608 /*//////////////////////////////////////////////////////////////////////////////
10610 
10611  Start of -include/epiworld/virus-bones.hpp-
10612 
10615 
10616 
10617 #ifndef EPIWORLD_VIRUS_HPP
10618 #define EPIWORLD_VIRUS_HPP
10619 
10620 template<typename TSeq>
10621 class Agent;
10622 
10623 template<typename TSeq>
10624 class Virus;
10625 
10626 template<typename TSeq>
10627 class Model;
10628 
10629 template<typename TSeq>
10630 class VirusFunctions {
10631 public:
10632  MutFun<TSeq> mutation = nullptr;
10633  PostRecoveryFun<TSeq> post_recovery = nullptr;
10634  VirusFun<TSeq> probability_of_infecting = nullptr;
10635  VirusFun<TSeq> probability_of_recovery = nullptr;
10636  VirusFun<TSeq> probability_of_death = nullptr;
10637  VirusFun<TSeq> incubation = nullptr;
10638 
10639  // Information about how distribution works
10640  VirusToAgentFun<TSeq> dist = nullptr;
10641 
10642  VirusFunctions() = default;
10643 
10644 };
10645 
10656 template<typename TSeq>
10657 class Virus {
10658  friend class Agent<TSeq>;
10659  friend class Model<TSeq>;
10660  friend class DataBase<TSeq>;
10661  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10662  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10663 private:
10664 
10665  Agent<TSeq> * agent = nullptr;
10666 
10667  EPI_TYPENAME_TRAITS(TSeq, int) baseline_sequence =
10668  EPI_TYPENAME_TRAITS(TSeq, int)();
10669 
10670  std::string virus_name = "unknown virus";
10671  int date = -99;
10672  int id = -99;
10673  epiworld_fast_int state_init = -99; ///< Change of state when added to agent.
10674  epiworld_fast_int state_post = -99; ///< Change of state when removed from agent.
10675  epiworld_fast_int state_removed = -99; ///< Change of state when agent is removed
10676 
10677  epiworld_fast_int queue_init = Queue<TSeq>::Everyone; ///< Change of state when added to agent.
10678  epiworld_fast_int queue_post = -Queue<TSeq>::Everyone; ///< Change of state when removed from agent.
10679  epiworld_fast_int queue_removed = -Queue<TSeq>::Everyone; ///< Change of state when agent is removed
10680 
10681  std::shared_ptr< VirusFunctions<TSeq> > virus_functions =
10682  std::make_shared< VirusFunctions<TSeq> >();
10683 
10684 public:
10685 
10686  #ifdef EPI_DEBUG_VIRUS
10687  static std::atomic<int> counter_construct; // Default and parameterized constructors
10688  static std::atomic<int> counter_copy_construct; // Copy constructor
10689  static std::atomic<int> counter_move_construct; // Move constructor
10690  static std::atomic<int> counter_copy_assign; // Copy assignment
10691  static std::atomic<int> counter_move_assign; // Move assignment
10692  static std::atomic<int> counter_destruct; // Destructor
10693  #endif
10694 
10695  Virus();
10696 
10697  Virus(std::string name = "unknown virus");
10698 
10699  Virus(
10700  std::string name,
10701  epiworld_double prevalence,
10702  bool as_proportion
10703  );
10704 
10705  #ifdef EPI_DEBUG_VIRUS
10706 
10707  // Copy and move operations for debugging
10708  Virus(const Virus<TSeq>& other); // Copy constructor
10709  Virus(Virus<TSeq>&& other) noexcept; // Move constructor
10710  Virus<TSeq>& operator=(const Virus<TSeq>& other); // Copy assignment
10711  Virus<TSeq>& operator=(Virus<TSeq>&& other) noexcept; // Move assignment
10712 
10713  ~Virus();
10714  #endif
10715 
10716  void mutate(Model<TSeq> * model);
10717  void set_mutation(MutFun<TSeq> fun);
10718 
10719  EPI_TYPENAME_TRAITS(TSeq, int) get_sequence();
10720  void set_sequence(TSeq sequence);
10721 
10722  Agent<TSeq> * get_agent();
10723  void set_agent(Agent<TSeq> * p);
10724 
10725  void set_date(int d);
10726  int get_date() const;
10727 
10728  void set_id(int idx);
10729  int get_id() const;
10730 
10740  epiworld_double get_prob_infecting(Model<TSeq> * model);
10741  epiworld_double get_prob_recovery(Model<TSeq> * model);
10742  epiworld_double get_prob_death(Model<TSeq> * model);
10743  epiworld_double get_incubation(Model<TSeq> * model);
10744 
10745  void post_recovery(Model<TSeq> * model);
10746  void set_post_recovery(PostRecoveryFun<TSeq> fun);
10747  void set_post_immunity(epiworld_double prob);
10748  void set_post_immunity(epiworld_double * prob);
10749 
10750  void set_prob_infecting_fun(VirusFun<TSeq> fun);
10751  void set_prob_recovery_fun(VirusFun<TSeq> fun);
10752  void set_prob_death_fun(VirusFun<TSeq> fun);
10753  void set_incubation_fun(VirusFun<TSeq> fun);
10754 
10755  void set_prob_infecting(const epiworld_double * prob);
10756  void set_prob_recovery(const epiworld_double * prob);
10757  void set_prob_death(const epiworld_double * prob);
10758  void set_incubation(const epiworld_double * prob);
10759 
10760  void set_prob_infecting(epiworld_double prob);
10761  void set_prob_recovery(epiworld_double prob);
10762  void set_prob_death(epiworld_double prob);
10763  void set_incubation(epiworld_double prob);
10765 
10766 
10767  void set_name(std::string name);
10768  std::string get_name() const;
10769 
10783  void set_state(
10784  epiworld_fast_int init,
10785  epiworld_fast_int end,
10786  epiworld_fast_int removed = -99
10787  );
10788 
10789  void set_queue(
10790  epiworld_fast_int init,
10791  epiworld_fast_int end,
10792  epiworld_fast_int removed = -99
10793  );
10794 
10795  void get_state(
10796  epiworld_fast_int * init,
10797  epiworld_fast_int * end,
10798  epiworld_fast_int * removed = nullptr
10799  );
10800 
10801  void get_queue(
10802  epiworld_fast_int * init,
10803  epiworld_fast_int * end,
10804  epiworld_fast_int * removed = nullptr
10805  );
10807 
10808  bool operator==(const Virus<TSeq> & other) const;
10809  bool operator!=(const Virus<TSeq> & other) const {return !operator==(other);};
10810 
10811  void print() const;
10812 
10817  void distribute(Model<TSeq> * model);
10818  void set_distribution(VirusToAgentFun<TSeq> fun);
10820 
10821 
10822 };
10823 
10824 #endif
10825 /*//////////////////////////////////////////////////////////////////////////////
10827 
10828  End of -include/epiworld/virus-bones.hpp-
10829 
10832 
10833 
10834 /*//////////////////////////////////////////////////////////////////////////////
10836 
10837  Start of -include/epiworld/agent-bones.hpp-
10838 
10841 
10842 
10843 #ifndef EPIWORLD_PERSON_BONES_HPP
10844 #define EPIWORLD_PERSON_BONES_HPP
10845 
10846 template<typename TSeq>
10847 class Model;
10848 
10849 template<typename TSeq>
10850 class Virus;
10851 
10852 template<typename TSeq>
10853 class Viruses;
10854 
10855 template<typename TSeq>
10856 class Viruses_const;
10857 
10858 template<typename TSeq>
10859 class Tool;
10860 
10861 template<typename TSeq>
10862 class Tools;
10863 
10864 template<typename TSeq>
10865 class Tools_const;
10866 
10867 template<typename TSeq>
10868 class Queue;
10869 
10870 template<typename TSeq>
10871 struct Event;
10872 
10873 template<typename TSeq>
10874 class Entity;
10875 
10876 template<typename TSeq>
10877 class Entities;
10878 
10879 template<typename TSeq>
10880 inline void default_add_virus(Event<TSeq> & a, Model<TSeq> * m);
10881 
10882 template<typename TSeq>
10883 inline void default_add_tool(Event<TSeq> & a, Model<TSeq> * m);
10884 
10885 template<typename TSeq>
10886 inline void default_add_entity(Event<TSeq> & a, Model<TSeq> * m);
10887 
10888 template<typename TSeq>
10889 inline void default_rm_virus(Event<TSeq> & a, Model<TSeq> * m);
10890 
10891 template<typename TSeq>
10892 inline void default_rm_tool(Event<TSeq> & a, Model<TSeq> * m);
10893 
10894 template<typename TSeq>
10895 inline void default_rm_entity(Event<TSeq> & a, Model<TSeq> * m);
10896 
10897 template<typename TSeq>
10898 inline void default_change_state(Event<TSeq> & a, Model<TSeq> * m);
10899 
10900 
10901 
10907 template<typename TSeq>
10908 class Agent {
10909  friend class Model<TSeq>;
10910  friend class Virus<TSeq>;
10911  friend class Tool<TSeq>;
10912  friend class Tools<TSeq>;
10913  friend class Tools_const<TSeq>;
10914  friend class Queue<TSeq>;
10915  friend class Entities<TSeq>;
10916  friend class AgentsSample<TSeq>;
10917  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10918  friend void default_add_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10919  friend void default_add_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10920  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10921  friend void default_rm_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10922  friend void default_rm_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10923  friend void default_change_state<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
10924 private:
10925 
10926  Model<TSeq> * model;
10927 
10928  std::vector< size_t > * neighbors = nullptr;
10929  std::vector< size_t > * neighbors_locations = nullptr;
10930  size_t n_neighbors = 0u;
10931 
10932  std::vector< size_t > entities;
10933  std::vector< size_t > entities_locations;
10934  size_t n_entities = 0u;
10935 
10936  unsigned int state = 0u;
10937  unsigned int state_prev = 0u; ///< For accounting, if need to undo a change.
10938 
10939  int state_last_changed = -1; ///< Last time the agent was updated.
10940  int id = -1;
10941 
10942  VirusPtr<TSeq> virus = nullptr;
10943 
10944  std::vector< ToolPtr<TSeq> > tools;
10945  unsigned int n_tools = 0u;
10946 
10947 public:
10948 
10949  Agent();
10950  Agent(Agent<TSeq> && p);
10951  Agent(const Agent<TSeq> & p);
10952  Agent<TSeq> & operator=(const Agent<TSeq> & other_agent);
10953  ~Agent();
10954 
10966  void add_tool(
10967  ToolPtr<TSeq> & tool,
10968  Model<TSeq> * model,
10969  epiworld_fast_int state_new = -99,
10970  epiworld_fast_int queue = -99
10971  );
10972 
10973  void add_tool(
10974  const Tool<TSeq> & tool,
10975  Model<TSeq> * model,
10976  epiworld_fast_int state_new = -99,
10977  epiworld_fast_int queue = -99
10978  );
10979 
10980  void set_virus(
10981  VirusPtr<TSeq> & virus,
10982  Model<TSeq> * model,
10983  epiworld_fast_int state_new = -99,
10984  epiworld_fast_int queue = -99
10985  );
10986 
10987  void set_virus(
10988  const Virus<TSeq> & virus,
10989  Model<TSeq> * model,
10990  epiworld_fast_int state_new = -99,
10991  epiworld_fast_int queue = -99
10992  );
10993 
10994  void add_entity(
10995  Entity<TSeq> & entity,
10996  Model<TSeq> * model,
10997  epiworld_fast_int state_new = -99,
10998  epiworld_fast_int queue = -99
10999  );
11000 
11001  void rm_tool(
11002  epiworld_fast_uint tool_idx,
11003  Model<TSeq> * model,
11004  epiworld_fast_int state_new = -99,
11005  epiworld_fast_int queue = -99
11006  );
11007 
11008  void rm_tool(
11009  ToolPtr<TSeq> & tool,
11010  Model<TSeq> * model,
11011  epiworld_fast_int state_new = -99,
11012  epiworld_fast_int queue = -99
11013  );
11014 
11015  void rm_virus(
11016  Model<TSeq> * model,
11017  epiworld_fast_int state_new = -99,
11018  epiworld_fast_int queue = -99
11019  );
11020 
11021  void rm_entity(
11022  epiworld_fast_uint entity_idx,
11023  Model<TSeq> * model,
11024  epiworld_fast_int state_new = -99,
11025  epiworld_fast_int queue = -99
11026  );
11027 
11028  void rm_entity(
11029  Entity<TSeq> & entity,
11030  Model<TSeq> * model,
11031  epiworld_fast_int state_new = -99,
11032  epiworld_fast_int queue = -99
11033  );
11034 
11035  void rm_agent_by_virus(Model<TSeq> * model); ///< Agent removed by virus
11037 
11045  epiworld_double get_susceptibility_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
11046  epiworld_double get_transmission_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
11047  epiworld_double get_recovery_enhancer(VirusPtr<TSeq> v, Model<TSeq> * model);
11048  epiworld_double get_death_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
11050 
11051  int get_id() const; ///< Id of the individual
11052 
11053  VirusPtr<TSeq> & get_virus();
11054  const VirusPtr<TSeq> & get_virus() const;
11055 
11056  ToolPtr<TSeq> & get_tool(int i);
11057  Tools<TSeq> get_tools();
11058  const Tools_const<TSeq> get_tools() const;
11059  size_t get_n_tools() const noexcept;
11060 
11061  void mutate_virus();
11062  void add_neighbor(
11063  Agent<TSeq> & p,
11064  bool check_source = true,
11065  bool check_target = true
11066  );
11067 
11075  void swap_neighbors(
11076  Agent<TSeq> & other,
11077  size_t n_this,
11078  size_t n_other
11079  );
11080 
11081  std::vector< Agent<TSeq> * > get_neighbors();
11082  size_t get_n_neighbors() const;
11083 
11084  void change_state(
11085  Model<TSeq> * model,
11086  epiworld_fast_uint new_state,
11087  epiworld_fast_int queue = 0
11088  );
11089 
11090  const unsigned int & get_state() const;
11091 
11092  void reset();
11093 
11094  bool has_tool(epiworld_fast_uint t) const;
11095  bool has_tool(std::string name) const;
11096  bool has_tool(const Tool<TSeq> & t) const;
11097  bool has_virus(epiworld_fast_uint t) const;
11098  bool has_virus(std::string name) const;
11099  bool has_virus(const Virus<TSeq> & v) const;
11100  bool has_entity(epiworld_fast_uint t) const;
11101  bool has_entity(std::string name) const;
11102 
11103  void print(bool compressed = false) const;
11104 
11121  double & operator()(size_t j);
11122  double & operator[](size_t j);
11123  double operator()(size_t j) const;
11124  double operator[](size_t j) const;
11126 
11127  Entities<TSeq> get_entities();
11128  const Entities_const<TSeq> get_entities() const;
11129  const Entity<TSeq> & get_entity(size_t i) const;
11130  Entity<TSeq> & get_entity(size_t i);
11131  size_t get_n_entities() const;
11132 
11133  bool operator==(const Agent<TSeq> & other) const;
11134  bool operator!=(const Agent<TSeq> & other) const {return !operator==(other);};
11135 
11136 };
11137 
11138 
11139 
11140 #endif
11141 /*//////////////////////////////////////////////////////////////////////////////
11143 
11144  End of -include/epiworld/agent-bones.hpp-
11145 
11148 
11149 
11150 
11169 template<typename TSeq>
11170 inline std::function<void(size_t,Model<TSeq>*)> make_save_run(
11171  std::string fmt,
11172  bool total_hist,
11173  bool virus_info,
11174  bool virus_hist,
11175  bool tool_info,
11176  bool tool_hist,
11177  bool transmission,
11178  bool transition,
11179  bool reproductive,
11180  bool generation
11181  )
11182 {
11183 
11184  // Counting number of %
11185  int n_fmt = 0;
11186  for (auto & f : fmt)
11187  if (f == '%')
11188  n_fmt++;
11189 
11190  if (n_fmt != 1)
11191  throw std::logic_error("The -fmt- argument must have only one \"%\" symbol.");
11192 
11193  // Listting things to save
11194  std::vector< bool > what_to_save = {
11195  virus_info,
11196  virus_hist,
11197  tool_info,
11198  tool_hist,
11199  total_hist,
11200  transmission,
11201  transition,
11202  reproductive,
11203  generation
11204  };
11205 
11206  std::function<void(size_t,Model<TSeq>*)> saver = [fmt,what_to_save](
11207  size_t niter, Model<TSeq> * m
11208  ) -> void {
11209 
11210  std::string virus_info = "";
11211  std::string virus_hist = "";
11212  std::string tool_info = "";
11213  std::string tool_hist = "";
11214  std::string total_hist = "";
11215  std::string transmission = "";
11216  std::string transition = "";
11217  std::string reproductive = "";
11218  std::string generation = "";
11219 
11220  char buff[1024u];
11221  if (what_to_save[0u])
11222  {
11223  virus_info = fmt + std::string("_virus_info.csv");
11224  snprintf(buff, sizeof(buff), virus_info.c_str(), niter);
11225  virus_info = buff;
11226  }
11227  if (what_to_save[1u])
11228  {
11229  virus_hist = fmt + std::string("_virus_hist.csv");
11230  snprintf(buff, sizeof(buff), virus_hist.c_str(), niter);
11231  virus_hist = buff;
11232  }
11233  if (what_to_save[2u])
11234  {
11235  tool_info = fmt + std::string("_tool_info.csv");
11236  snprintf(buff, sizeof(buff), tool_info.c_str(), niter);
11237  tool_info = buff;
11238  }
11239  if (what_to_save[3u])
11240  {
11241  tool_hist = fmt + std::string("_tool_hist.csv");
11242  snprintf(buff, sizeof(buff), tool_hist.c_str(), niter);
11243  tool_hist = buff;
11244  }
11245  if (what_to_save[4u])
11246  {
11247  total_hist = fmt + std::string("_total_hist.csv");
11248  snprintf(buff, sizeof(buff), total_hist.c_str(), niter);
11249  total_hist = buff;
11250  }
11251  if (what_to_save[5u])
11252  {
11253  transmission = fmt + std::string("_transmission.csv");
11254  snprintf(buff, sizeof(buff), transmission.c_str(), niter);
11255  transmission = buff;
11256  }
11257  if (what_to_save[6u])
11258  {
11259  transition = fmt + std::string("_transition.csv");
11260  snprintf(buff, sizeof(buff), transition.c_str(), niter);
11261  transition = buff;
11262  }
11263  if (what_to_save[7u])
11264  {
11265 
11266  reproductive = fmt + std::string("_reproductive.csv");
11267  snprintf(buff, sizeof(buff), reproductive.c_str(), niter);
11268  reproductive = buff;
11269 
11270  }
11271  if (what_to_save[8u])
11272  {
11273 
11274  generation = fmt + std::string("_generation.csv");
11275  snprintf(buff, sizeof(buff), generation.c_str(), niter);
11276  generation = buff;
11277 
11278  }
11279 
11280 
11281  m->write_data(
11282  virus_info,
11283  virus_hist,
11284  tool_info,
11285  tool_hist,
11286  total_hist,
11287  transmission,
11288  transition,
11289  reproductive,
11290  generation
11291  );
11292 
11293  };
11294 
11295  return saver;
11296 }
11297 
11298 
11299 template<typename TSeq>
11300 inline void Model<TSeq>::events_add(
11301  Agent<TSeq> * agent_,
11302  VirusPtr<TSeq> virus_,
11303  ToolPtr<TSeq> tool_,
11304  Entity<TSeq> * entity_,
11305  epiworld_fast_int new_state_,
11306  epiworld_fast_int queue_,
11307  EventFun<TSeq> call_,
11308  int idx_agent_,
11309  int idx_object_
11310 ) {
11311 
11312  ++nactions;
11313 
11314  #ifdef EPI_DEBUG
11315  if (nactions == 0)
11316  throw std::logic_error("Events cannot be zero!!");
11317  #endif
11318 
11319  if (nactions > events.size())
11320  {
11321 
11322  events.emplace_back(
11323  Event<TSeq>(
11324  agent_, virus_, tool_, entity_, new_state_, queue_, call_,
11325  idx_agent_, idx_object_
11326  ));
11327 
11328  }
11329  else
11330  {
11331 
11332  Event<TSeq> & A = events.at(nactions - 1u);
11333 
11334  A.agent = std::move(agent_);
11335  A.virus = std::move(virus_);
11336  A.tool = std::move(tool_);
11337  A.entity = std::move(entity_);
11338  A.new_state = std::move(new_state_);
11339  A.queue = std::move(queue_);
11340  A.call = std::move(call_);
11341  A.idx_agent = std::move(idx_agent_);
11342  A.idx_object = std::move(idx_object_);
11343 
11344  }
11345 
11346  return;
11347 
11348 }
11349 
11350 template<typename TSeq>
11351 inline void Model<TSeq>::events_run()
11352 {
11353  // Making the call
11354  size_t nevents_tmp = 0;
11355  while (nevents_tmp < nactions)
11356  {
11357 
11358  Event<TSeq> & a = events[nevents_tmp++];
11359  Agent<TSeq> * p = a.agent;
11360 
11361  #ifdef EPI_DEBUG
11362  if (a.new_state >= static_cast<epiworld_fast_int>(nstates))
11363  {
11364  throw std::range_error(
11365  "The proposed state " + std::to_string(a.new_state) + " is out of range. " +
11366  "The model currently has " + std::to_string(nstates - 1) + " states.");
11367 
11368  }
11369  else if ((a.new_state != -99) && (a.new_state < 0))
11370  {
11371  throw std::range_error(
11372  "The proposed state " + std::to_string(a.new_state) + " is out of range. " +
11373  "The state cannot be negative.");
11374  }
11375  #endif
11376 
11377  // Undoing the change in the transition matrix
11378  if (
11379  (a.new_state != -99) &&
11380  (p->state_last_changed == today()) &&
11381  (static_cast<int>(p->state) != a.new_state)
11382  )
11383  {
11384  // Undoing state change in the transition matrix
11385  // The previous state is already recorded
11386  db.update_state(p->state_prev, p->state, true);
11387 
11388  } else if (p->state_last_changed != today())
11389  p->state_prev = p->state; // Recording the previous state
11390 
11391  // Applying function after the fact. This way, if there were
11392  // updates, they can be recorded properly, before losing the information
11393  if (a.call)
11394  {
11395  a.call(a, this);
11396  }
11397 
11398  if (a.new_state != -99)
11399  p->state = a.new_state;
11400 
11401  // Registering that the last change was today
11402  p->state_last_changed = today();
11403 
11404 
11405  #ifdef EPI_DEBUG
11406  if (static_cast<int>(p->state) >= static_cast<int>(nstates))
11407  throw std::range_error(
11408  "The new state " + std::to_string(p->state) + " is out of range. " +
11409  "The model currently has " + std::to_string(nstates - 1) + " states.");
11410  #endif
11411 
11412  // Updating queue
11413  if (use_queuing && a.queue != -99)
11414  {
11415 
11416  if (a.queue == Queue<TSeq>::Everyone)
11417  queue += p;
11418  else if (a.queue == -Queue<TSeq>::Everyone)
11419  queue -= p;
11420  else if (a.queue == Queue<TSeq>::OnlySelf)
11421  queue[p->get_id()]++;
11422  else if (a.queue == -Queue<TSeq>::OnlySelf)
11423  queue[p->get_id()]--;
11424  else if (a.queue != Queue<TSeq>::NoOne)
11425  throw std::logic_error(
11426  "The proposed queue change is not valid. Queue values can be {-2, -1, 0, 1, 2}."
11427  );
11428 
11429  }
11430 
11431  }
11432 
11433  // Go back to square 1
11434  nactions = 0u;
11435 
11436  return;
11437 
11438 }
11439 
11448 template<typename TSeq>
11449 inline epiworld_double susceptibility_reduction_mixer_default(
11450  Agent<TSeq>* p,
11451  VirusPtr<TSeq> v,
11452  Model<TSeq> * m
11453 )
11454 {
11455  epiworld_double total = 1.0;
11456  for (auto & tool : p->get_tools())
11457  total *= (1.0 - tool->get_susceptibility_reduction(v, m));
11458 
11459  return 1.0 - total;
11460 
11461 }
11462 
11463 template<typename TSeq>
11464 inline epiworld_double transmission_reduction_mixer_default(
11465  Agent<TSeq>* p,
11466  VirusPtr<TSeq> v,
11467  Model<TSeq>* m
11468 )
11469 {
11470  epiworld_double total = 1.0;
11471  for (auto & tool : p->get_tools())
11472  total *= (1.0 - tool->get_transmission_reduction(v, m));
11473 
11474  return (1.0 - total);
11475 
11476 }
11477 
11478 template<typename TSeq>
11479 inline epiworld_double recovery_enhancer_mixer_default(
11480  Agent<TSeq>* p,
11481  VirusPtr<TSeq> v,
11482  Model<TSeq>* m
11483 )
11484 {
11485  epiworld_double total = 1.0;
11486  for (auto & tool : p->get_tools())
11487  total *= (1.0 - tool->get_recovery_enhancer(v, m));
11488 
11489  return 1.0 - total;
11490 
11491 }
11492 
11493 template<typename TSeq>
11494 inline epiworld_double death_reduction_mixer_default(
11495  Agent<TSeq>* p,
11496  VirusPtr<TSeq> v,
11497  Model<TSeq>* m
11498 ) {
11499 
11500  epiworld_double total = 1.0;
11501  for (auto & tool : p->get_tools())
11502  {
11503  total *= (1.0 - tool->get_death_reduction(v, m));
11504  }
11505 
11506  return 1.0 - total;
11507 
11508 }
11510 
11511 template<typename TSeq>
11512 inline Model<TSeq> * Model<TSeq>::clone_ptr()
11513 {
11514  // Everything is copied
11515  Model<TSeq> * ptr = new Model<TSeq>(*dynamic_cast<const Model<TSeq>*>(this));
11516 
11517  #ifdef EPI_DEBUG
11518  if (*this != *ptr)
11519  throw std::logic_error("Model::clone_ptr The copies of the model don't match.");
11520  #endif
11521 
11522  return ptr;
11523 }
11524 
11525 template<typename TSeq>
11526 inline Model<TSeq>::Model()
11527 {
11528  db.model = this;
11529  db.user_data = this;
11530  if (use_queuing)
11531  queue.model = this;
11532 }
11533 
11534 template<typename TSeq>
11535 inline Model<TSeq>::Model(const Model<TSeq> & model) :
11536  name(model.name),
11537  db(model.db),
11538  population(model.population),
11539  population_backup(model.population_backup),
11540  directed(model.directed),
11541  viruses(model.viruses),
11542  tools(model.tools),
11543  entities(model.entities),
11544  entities_backup(model.entities_backup),
11545  rewire_fun(model.rewire_fun),
11546  rewire_prop(model.rewire_prop),
11547  parameters(model.parameters),
11548  ndays(model.ndays),
11549  pb(model.pb),
11550  state_fun(model.state_fun),
11551  states_labels(model.states_labels),
11552  initial_states_fun(model.initial_states_fun),
11553  nstates(model.nstates),
11554  verbose(model.verbose),
11555  current_date(model.current_date),
11556  globalevents(model.globalevents),
11557  queue(model.queue),
11558  use_queuing(model.use_queuing),
11559  array_double_tmp(model.array_double_tmp.size()),
11560  array_virus_tmp(model.array_virus_tmp.size())
11561 {
11562 
11563 
11564  // Removing old neighbors
11565  for (auto & p : population)
11566  p.model = this;
11567 
11568  // Pointing to the right place. This needs
11569  // to be done afterwards since the state zero is set as a function
11570  // of the population.
11571  db.model = this;
11572  db.user_data.model = this;
11573 
11574  if (use_queuing)
11575  queue.model = this;
11576 
11577  agents_data = model.agents_data;
11578  agents_data_ncols = model.agents_data_ncols;
11579 
11580 }
11581 
11582 template<typename TSeq>
11583 inline Model<TSeq>::Model(Model<TSeq> & model) :
11584  Model(dynamic_cast< const Model<TSeq> & >(model)) {}
11585 
11586 template<typename TSeq>
11587 inline Model<TSeq>::Model(Model<TSeq> && model) :
11588  name(std::move(model.name)),
11589  db(std::move(model.db)),
11590  population(std::move(model.population)),
11591  agents_data(std::move(model.agents_data)),
11592  agents_data_ncols(std::move(model.agents_data_ncols)),
11593  directed(std::move(model.directed)),
11594  // Virus
11595  viruses(std::move(model.viruses)),
11596  // Tools
11597  tools(std::move(model.tools)),
11598  // Entities
11599  entities(std::move(model.entities)),
11600  entities_backup(std::move(model.entities_backup)),
11601  // Pseudo-RNG
11602  engine(std::move(model.engine)),
11603  runifd(std::move(model.runifd)),
11604  rnormd(std::move(model.rnormd)),
11605  rgammad(std::move(model.rgammad)),
11606  rlognormald(std::move(model.rlognormald)),
11607  rexpd(std::move(model.rexpd)),
11608  // Rewiring
11609  rewire_fun(std::move(model.rewire_fun)),
11610  rewire_prop(std::move(model.rewire_prop)),
11611  parameters(std::move(model.parameters)),
11612  // Others
11613  ndays(model.ndays),
11614  pb(std::move(model.pb)),
11615  state_fun(std::move(model.state_fun)),
11616  states_labels(std::move(model.states_labels)),
11617  initial_states_fun(std::move(model.initial_states_fun)),
11618  nstates(model.nstates),
11619  verbose(model.verbose),
11620  current_date(std::move(model.current_date)),
11621  globalevents(std::move(model.globalevents)),
11622  queue(std::move(model.queue)),
11623  use_queuing(model.use_queuing),
11624  array_double_tmp(model.array_double_tmp.size()),
11625  array_virus_tmp(model.array_virus_tmp.size())
11626 {
11627 
11628  db.model = this;
11629  db.user_data.model = this;
11630 
11631  if (use_queuing)
11632  queue.model = this;
11633 
11634 }
11635 
11636 template<typename TSeq>
11637 inline Model<TSeq> & Model<TSeq>::operator=(const Model<TSeq> & m)
11638 {
11639  name = m.name;
11640 
11641  population = m.population;
11642  population_backup = m.population_backup;
11643 
11644  for (auto & p : population)
11645  p.model = this;
11646 
11647  db = m.db;
11648  db.model = this;
11649  db.user_data.model = this;
11650 
11651  directed = m.directed;
11652 
11653  viruses = m.viruses;
11654 
11655  tools = m.tools;
11656 
11657  entities = m.entities;
11658  entities_backup = m.entities_backup;
11659 
11660  rewire_fun = m.rewire_fun;
11661  rewire_prop = m.rewire_prop;
11662 
11663  parameters = m.parameters;
11664  ndays = m.ndays;
11665  pb = m.pb;
11666 
11667  state_fun = m.state_fun;
11668  states_labels = m.states_labels;
11669  initial_states_fun = m.initial_states_fun;
11670  nstates = m.nstates;
11671 
11672  verbose = m.verbose;
11673 
11674  current_date = m.current_date;
11675 
11676  globalevents = m.globalevents;
11677 
11678  queue = m.queue;
11679  use_queuing = m.use_queuing;
11680 
11681  // Making sure population is passed correctly
11682  // Pointing to the right place
11683  db.model = this;
11684  db.user_data.model = this;
11685 
11686  agents_data = m.agents_data;
11687  agents_data_ncols = m.agents_data_ncols;
11688 
11689  // Figure out the queuing
11690  if (use_queuing)
11691  queue.model = this;
11692 
11693  array_double_tmp.resize(static_cast<size_t>(1024u), 0.0);
11694  array_virus_tmp.resize(1024u);
11695 
11696  return *this;
11697 
11698 }
11699 
11700 template<typename TSeq>
11701 inline DataBase<TSeq> & Model<TSeq>::get_db()
11702 {
11703  return db;
11704 }
11705 
11706 template<typename TSeq>
11707 inline const DataBase<TSeq> & Model<TSeq>::get_db() const
11708 {
11709  return db;
11710 }
11711 
11712 
11713 template<typename TSeq>
11714 inline std::vector<Agent<TSeq>> & Model<TSeq>::get_agents()
11715 {
11716  return population;
11717 }
11718 
11719 template<typename TSeq>
11720 inline Agent<TSeq> & Model<TSeq>::get_agent(size_t i)
11721 {
11722  return population[i];
11723 }
11724 
11725 template<typename TSeq>
11726 inline std::vector< epiworld_fast_uint > Model<TSeq>::get_agents_states() const
11727 {
11728  std::vector< epiworld_fast_uint > states(population.size());
11729  for (size_t i = 0u; i < population.size(); ++i)
11730  states[i] = population[i].get_state();
11731 
11732  return states;
11733 }
11734 
11735 template<typename TSeq>
11736 inline std::vector< Viruses_const<TSeq> > Model<TSeq>::get_agents_viruses() const
11737 {
11738 
11739  std::vector< Viruses_const<TSeq> > viruses(population.size());
11740  for (size_t i = 0u; i < population.size(); ++i)
11741  viruses[i] = population[i].get_virus();
11742 
11743  return viruses;
11744 
11745 }
11746 
11747 // Same as before, but the non const version
11748 template<typename TSeq>
11749 inline std::vector< Viruses<TSeq> > Model<TSeq>::get_agents_viruses()
11750 {
11751 
11752  std::vector< Viruses<TSeq> > viruses(population.size());
11753  for (size_t i = 0u; i < population.size(); ++i)
11754  viruses[i] = population[i].get_virus();
11755 
11756  return viruses;
11757 
11758 }
11759 
11760 template<typename TSeq>
11761 inline std::vector<Entity<TSeq>> & Model<TSeq>::get_entities()
11762 {
11763  return entities;
11764 }
11765 
11766 template<typename TSeq>
11767 inline Entity<TSeq> & Model<TSeq>::get_entity(size_t i, int * entity_pos)
11768 {
11769 
11770  for (size_t j = 0u; j < entities.size(); ++j)
11771  if (entities[j].get_id() == static_cast<int>(i))
11772  {
11773 
11774  if (entity_pos)
11775  *entity_pos = j;
11776 
11777  return entities[j];
11778 
11779  }
11780 
11781  throw std::range_error("The entity with id " + std::to_string(i) + " was not found.");
11782 
11783 }
11784 
11785 template<typename TSeq>
11786 inline Model<TSeq> & Model<TSeq>::agents_smallworld(
11787  epiworld_fast_uint n,
11788  epiworld_fast_uint k,
11789  bool d,
11790  epiworld_double p
11791 )
11792 {
11793  agents_from_adjlist(
11794  rgraph_smallworld(n, k, p, d, *this)
11795  );
11796 
11797  return *this;
11798 }
11799 
11800 template<typename TSeq>
11801 inline void Model<TSeq>::agents_empty_graph(
11802  epiworld_fast_uint n
11803 )
11804 {
11805 
11806  // Resizing the people
11807  population.clear();
11808  population.resize(n, Agent<TSeq>());
11809 
11810  // Filling the model and ids
11811  size_t i = 0u;
11812  for (auto & p : population)
11813  {
11814  p.id = i++;
11815  p.model = this;
11816  }
11817 
11818 
11819 }
11820 
11821 template<typename TSeq>
11822 inline void Model<TSeq>::set_rand_gamma(epiworld_double alpha, epiworld_double beta)
11823 {
11824  rgammad = std::gamma_distribution<>(alpha,beta);
11825 }
11826 
11827 template<typename TSeq>
11828 inline void Model<TSeq>::set_rand_norm(epiworld_double mean, epiworld_double sd)
11829 {
11830  rnormd = std::normal_distribution<>(mean, sd);
11831 }
11832 
11833 template<typename TSeq>
11834 inline void Model<TSeq>::set_rand_unif(epiworld_double a, epiworld_double b)
11835 {
11836  runifd = std::uniform_real_distribution<>(a, b);
11837 }
11838 
11839 template<typename TSeq>
11840 inline void Model<TSeq>::set_rand_lognormal(epiworld_double mean, epiworld_double shape)
11841 {
11842  rlognormald = std::lognormal_distribution<>(mean, shape);
11843 }
11844 
11845 template<typename TSeq>
11846 inline void Model<TSeq>::set_rand_exp(epiworld_double lambda)
11847 {
11848  rexpd = std::exponential_distribution<>(lambda);
11849 }
11850 
11851 template<typename TSeq>
11852 inline void Model<TSeq>::set_rand_binom(int n, epiworld_double p)
11853 {
11854  rbinomd = std::binomial_distribution<>(n, p);
11855 }
11856 
11857 template<typename TSeq>
11858 inline void Model<TSeq>::set_rand_nbinom(int n, epiworld_double p)
11859 {
11860  rnbinomd = std::negative_binomial_distribution<>(n, p);
11861 }
11862 
11863 template<typename TSeq>
11864 inline void Model<TSeq>::set_rand_geom(epiworld_double p)
11865 {
11866  rgeomd = std::geometric_distribution<>(p);
11867 }
11868 
11869 template<typename TSeq>
11870 inline void Model<TSeq>::set_rand_poiss(epiworld_double lambda)
11871 {
11872  rpoissd = std::poisson_distribution<>(lambda);
11873 }
11874 
11875 template<typename TSeq>
11876 inline epiworld_double & Model<TSeq>::operator()(std::string pname) {
11877 
11878  if (parameters.find(pname) == parameters.end())
11879  throw std::range_error("The parameter '"+ pname + "' is not in the model.");
11880 
11881  return parameters[pname];
11882 
11883 }
11884 
11885 template<typename TSeq>
11886 inline size_t Model<TSeq>::size() const {
11887  return population.size();
11888 }
11889 
11890 template<typename TSeq>
11891 inline void Model<TSeq>::dist_virus()
11892 {
11893 
11894  for (auto & v: viruses)
11895  {
11896 
11897  v->distribute(this);
11898 
11899  // Apply the events
11900  events_run();
11901  }
11902 
11903 }
11904 
11905 template<typename TSeq>
11906 inline void Model<TSeq>::dist_tools()
11907 {
11908 
11909  for (auto & tool: tools)
11910  {
11911 
11912  tool->distribute(this);
11913 
11914  // Apply the events
11915  events_run();
11916 
11917  }
11918 
11919 }
11920 
11921 template<typename TSeq>
11922 inline void Model<TSeq>::dist_entities()
11923 {
11924 
11925  for (auto & entity: entities)
11926  {
11927 
11928  entity.distribute(this);
11929 
11930  // Apply the events
11931  events_run();
11932 
11933  }
11934 
11935 }
11936 
11937 template<typename TSeq>
11938 inline void Model<TSeq>::chrono_start() {
11939  time_start = std::chrono::steady_clock::now();
11940 }
11941 
11942 template<typename TSeq>
11943 inline void Model<TSeq>::chrono_end() {
11944  time_end = std::chrono::steady_clock::now();
11945  time_elapsed += (time_end - time_start);
11946  n_replicates++;
11947 }
11948 
11949 template<typename TSeq>
11950 inline void Model<TSeq>::set_backup()
11951 {
11952 
11953  if (population_backup.size() == 0u)
11954  population_backup = std::vector< Agent<TSeq> >(population);
11955 
11956  if (entities_backup.size() == 0u)
11957  entities_backup = std::vector< Entity<TSeq> >(entities);
11958 
11959 }
11960 
11961 template<typename TSeq>
11962 inline std::shared_ptr< std::mt19937 > & Model<TSeq>::get_rand_endgine()
11963 {
11964  return engine;
11965 }
11966 
11967 template<typename TSeq>
11968 inline epiworld_double Model<TSeq>::runif() {
11969  // CHECK_INIT()
11970  return runifd(*engine);
11971 }
11972 
11973 template<typename TSeq>
11974 inline epiworld_double Model<TSeq>::runif(epiworld_double a, epiworld_double b) {
11975  // CHECK_INIT()
11976  return runifd(*engine) * (b - a) + a;
11977 }
11978 
11979 template<typename TSeq>
11980 inline epiworld_double Model<TSeq>::rnorm() {
11981  // CHECK_INIT()
11982  return rnormd(*engine);
11983 }
11984 
11985 template<typename TSeq>
11986 inline epiworld_double Model<TSeq>::rnorm(epiworld_double mean, epiworld_double sd) {
11987  // CHECK_INIT()
11988  return rnormd(*engine) * sd + mean;
11989 }
11990 
11991 template<typename TSeq>
11992 inline epiworld_double Model<TSeq>::rgamma() {
11993  return rgammad(*engine);
11994 }
11995 
11996 template<typename TSeq>
11997 inline epiworld_double Model<TSeq>::rgamma(epiworld_double alpha, epiworld_double beta) {
11998 
11999  return rgammad(
12000  *engine,
12001  std::gamma_distribution<>::param_type(alpha, beta)
12002  );
12003 
12004 }
12005 
12006 template<typename TSeq>
12007 inline epiworld_double Model<TSeq>::rexp() {
12008  return rexpd(*engine);
12009 }
12010 
12011 template<typename TSeq>
12012 inline epiworld_double Model<TSeq>::rexp(epiworld_double lambda) {
12013 
12014  return rexpd(
12015  *engine,
12016  std::exponential_distribution<>::param_type(lambda)
12017  );
12018 
12019 }
12020 
12021 template<typename TSeq>
12022 inline epiworld_double Model<TSeq>::rlognormal() {
12023  return rlognormald(*engine);
12024 }
12025 
12026 template<typename TSeq>
12027 inline epiworld_double Model<TSeq>::rlognormal(epiworld_double mean, epiworld_double shape) {
12028 
12029  return rlognormald(
12030  *engine,
12031  std::lognormal_distribution<>::param_type(mean, shape)
12032  );
12033 }
12034 
12035 template<typename TSeq>
12036 inline int Model<TSeq>::rbinom() {
12037  return rbinomd(*engine);
12038 }
12039 
12040 template<typename TSeq>
12041 inline int Model<TSeq>::rbinom(int n, epiworld_double p) {
12042 
12043  if (n == 0 || p == 0.0)
12044  return 0;
12045 
12046  return rbinomd(
12047  *engine,
12048  std::binomial_distribution<>::param_type(n, p)
12049  );
12050 
12051 }
12052 
12053 template<typename TSeq>
12054 inline int Model<TSeq>::rnbinom() {
12055  return rnbinomd(*engine);
12056 }
12057 
12058 template<typename TSeq>
12059 inline int Model<TSeq>::rnbinom(int n, epiworld_double p) {
12060 
12061  return rnbinomd(
12062  *engine,
12063  std::negative_binomial_distribution<>::param_type(n, p)
12064  );
12065 }
12066 
12067 template<typename TSeq>
12068 inline int Model<TSeq>::rgeom() {
12069  return rgeomd(*engine);
12070 }
12071 
12072 template<typename TSeq>
12073 inline int Model<TSeq>::rgeom(epiworld_double p) {
12074 
12075  return rgeomd(
12076  *engine,
12077  std::geometric_distribution<>::param_type(p)
12078  );
12079 
12080 }
12081 
12082 template<typename TSeq>
12083 inline int Model<TSeq>::rpoiss() {
12084  return rpoissd(*engine);
12085 }
12086 
12087 template<typename TSeq>
12088 inline int Model<TSeq>::rpoiss(epiworld_double lambda) {
12089 
12090  return rpoissd(
12091  *engine,
12092  std::poisson_distribution<>::param_type(lambda)
12093  );
12094 
12095 }
12096 
12097 template<typename TSeq>
12098 inline void Model<TSeq>::seed(size_t s) {
12099  this->engine->seed(s);
12100 }
12101 
12102 template<typename TSeq>
12103 inline void Model<TSeq>::add_virus(
12104  Virus<TSeq> & v
12105  )
12106 {
12107 
12108  // Checking the state
12109  epiworld_fast_int init_, post_, rm_;
12110  v.get_state(&init_, &post_, &rm_);
12111 
12112  if (init_ == -99)
12113  throw std::logic_error(
12114  "The virus \"" + v.get_name() + "\" has no -init- state."
12115  );
12116  else if (post_ == -99)
12117  throw std::logic_error(
12118  "The virus \"" + v.get_name() + "\" has no -post- state."
12119  );
12120 
12121  // Recording the variant
12122  db.record_virus(v);
12123 
12124  // Adding new virus
12125  viruses.push_back(std::make_shared< Virus<TSeq> >(v));
12126 
12127 }
12128 
12129 template<typename TSeq>
12130 inline void Model<TSeq>::add_tool(Tool<TSeq> & t)
12131 {
12132 
12133 
12134  db.record_tool(t);
12135 
12136  // Adding the tool to the model (and database.)
12137  tools.push_back(std::make_shared< Tool<TSeq> >(t));
12138 
12139 }
12140 
12141 template<typename TSeq>
12142 inline void Model<TSeq>::add_entity(Entity<TSeq> e)
12143 {
12144 
12145  e.id = entities.size();
12146  entities.push_back(e);
12147 
12148 }
12149 
12150 template<typename TSeq>
12151 inline void Model<TSeq>::rm_entity(size_t entity_id)
12152 {
12153 
12154  int entity_pos = 0;
12155  auto & entity = this->get_entity(entity_id, &entity_pos);
12156 
12157  // First, resetting the entity
12158  entity.reset();
12159 
12160  // How should
12161  if (entity_pos != (static_cast<int>(entities.size()) - 1))
12162  std::swap(entities[entity_pos], entities[entities.size() - 1]);
12163 
12164  entities.pop_back();
12165 }
12166 
12167 template<typename TSeq>
12168 inline void Model<TSeq>::rm_virus(size_t virus_pos)
12169 {
12170 
12171  if (viruses.size() <= virus_pos)
12172  throw std::range_error(
12173  std::string("The specified virus (") +
12174  std::to_string(virus_pos) +
12175  std::string(") is out of range. ") +
12176  std::string("There are only ") +
12177  std::to_string(viruses.size()) +
12178  std::string(" viruses.")
12179  );
12180 
12181  // Flipping with the last one
12182  std::swap(viruses[virus_pos], viruses[viruses.size() - 1]);
12183  viruses.pop_back();
12184 
12185  return;
12186 
12187 }
12188 
12189 template<typename TSeq>
12190 inline void Model<TSeq>::rm_tool(size_t tool_pos)
12191 {
12192 
12193  if (tools.size() <= tool_pos)
12194  throw std::range_error(
12195  std::string("The specified tool (") +
12196  std::to_string(tool_pos) +
12197  std::string(") is out of range. ") +
12198  std::string("There are only ") +
12199  std::to_string(tools.size()) +
12200  std::string(" tools.")
12201  );
12202 
12203  // Flipping with the last one
12204  std::swap(tools[tool_pos], tools[tools.size() - 1]);
12205 
12206  /* There's an error on windows:
12207  https://github.com/UofUEpiBio/epiworldR/actions/runs/4801482395/jobs/8543744180#step:6:84
12208 
12209  More clear here:
12210  https://stackoverflow.com/questions/58660207/why-doesnt-stdswap-work-on-vectorbool-elements-under-clang-win
12211  */
12212 
12213  tools.pop_back();
12214 
12215  return;
12216 
12217 }
12218 
12219 template<typename TSeq>
12221  std::string fn,
12222  int skip
12223  )
12224 {
12225 
12226  int i,j;
12227  std::ifstream filei(fn);
12228 
12229  if (!filei)
12230  throw std::logic_error("The file " + fn + " was not found.");
12231 
12232  int linenum = 0;
12233  std::vector< std::vector< epiworld_fast_uint > > target_(entities.size());
12234 
12235  target_.reserve(1e5);
12236 
12237  while (!filei.eof())
12238  {
12239 
12240  if (linenum++ < skip)
12241  continue;
12242 
12243  filei >> i >> j;
12244 
12245  // Looking for exceptions
12246  if (filei.bad())
12247  throw std::logic_error(
12248  "I/O error while reading the file " +
12249  fn
12250  );
12251 
12252  if (filei.fail())
12253  break;
12254 
12255  if (i >= static_cast<int>(this->size()))
12256  throw std::range_error(
12257  "The agent["+std::to_string(linenum)+"] = " + std::to_string(i) +
12258  " is above the max id " + std::to_string(this->size() - 1)
12259  );
12260 
12261  if (j >= static_cast<int>(this->entities.size()))
12262  throw std::range_error(
12263  "The entity["+std::to_string(linenum)+"] = " + std::to_string(j) +
12264  " is above the max id " + std::to_string(this->entities.size() - 1)
12265  );
12266 
12267  target_[j].push_back(i);
12268 
12269  population[i].add_entity(entities[j], nullptr);
12270 
12271  }
12272 
12273  return;
12274 
12275 }
12276 
12277 template<typename TSeq>
12279  const std::vector< int > & agents_ids,
12280  const std::vector< int > & entities_ids
12281 ) {
12282 
12283  // Checking the size
12284  if (agents_ids.size() != entities_ids.size())
12285  throw std::length_error(
12286  std::string("The size of agents_ids (") +
12287  std::to_string(agents_ids.size()) +
12288  std::string(") and entities_ids (") +
12289  std::to_string(entities_ids.size()) +
12290  std::string(") must be the same.")
12291  );
12292 
12293  return this->load_agents_entities_ties(
12294  agents_ids.data(),
12295  entities_ids.data(),
12296  agents_ids.size()
12297  );
12298 
12299 }
12300 
12301 template<typename TSeq>
12303  const int * agents_ids,
12304  const int * entities_ids,
12305  size_t n
12306 ) {
12307 
12308  auto get_agent = [agents_ids](int i) -> int {
12309  return *(agents_ids + i);
12310  };
12311 
12312  auto get_entity = [entities_ids](int i) -> int {
12313  return *(entities_ids + i);
12314  };
12315 
12316  for (size_t i = 0u; i < n; ++i)
12317  {
12318 
12319  if (get_agent(i) < 0)
12320  throw std::length_error(
12321  std::string("agents_ids[") +
12322  std::to_string(i) +
12323  std::string("] = ") +
12324  std::to_string(get_agent(i)) +
12325  std::string(" is negative.")
12326  );
12327 
12328  if (get_entity(i) < 0)
12329  throw std::length_error(
12330  std::string("entities_ids[") +
12331  std::to_string(i) +
12332  std::string("] = ") +
12333  std::to_string(get_entity(i)) +
12334  std::string(" is negative.")
12335  );
12336 
12337  int pop_size = static_cast<int>(this->population.size());
12338  if (get_agent(i) >= pop_size)
12339  throw std::length_error(
12340  std::string("agents_ids[") +
12341  std::to_string(i) +
12342  std::string("] = ") +
12343  std::to_string(get_agent(i)) +
12344  std::string(" is out of range (population size: ") +
12345  std::to_string(pop_size) +
12346  std::string(").")
12347  );
12348 
12349  int ent_size = static_cast<int>(this->entities.size());
12350  if (get_entity(i) >= ent_size)
12351  throw std::length_error(
12352  std::string("entities_ids[") +
12353  std::to_string(i) +
12354  std::string("] = ") +
12355  std::to_string(get_entity(i)) +
12356  std::string(" is out of range (entities size: ") +
12357  std::to_string(ent_size) +
12358  std::string(").")
12359  );
12360 
12361  // Adding the entity to the agent
12362  this->population[get_agent(i)].add_entity(
12363  this->entities[get_entity(i)],
12364  nullptr /* Immediately add it to the agent */
12365  );
12366 
12367  }
12368 
12369  return;
12370 
12371 
12372 }
12373 
12374 template<typename TSeq>
12376  std::string fn,
12377  int size,
12378  int skip,
12379  bool directed
12380  ) {
12381 
12382  AdjList al;
12383  al.read_edgelist(fn, size, skip, directed);
12384  this->agents_from_adjlist(al);
12385 
12386 }
12387 
12388 template<typename TSeq>
12390  const std::vector< int > & source,
12391  const std::vector< int > & target,
12392  int size,
12393  bool directed
12394 ) {
12395 
12396  AdjList al(source, target, size, directed);
12397  agents_from_adjlist(al);
12398 
12399 }
12400 
12401 template<typename TSeq>
12402 inline void Model<TSeq>::agents_from_adjlist(AdjList al) {
12403 
12404  // Resizing the people
12405  agents_empty_graph(al.vcount());
12406 
12407  const auto & tmpdat = al.get_dat();
12408 
12409  for (size_t i = 0u; i < tmpdat.size(); ++i)
12410  {
12411 
12412  // population[i].id = i;
12413  population[i].model = this;
12414 
12415  for (const auto & link: tmpdat[i])
12416  {
12417 
12418  population[i].add_neighbor(
12419  population[link.first],
12420  true, true
12421  );
12422 
12423  }
12424 
12425  }
12426 
12427  #ifdef EPI_DEBUG
12428  for (auto & p: population)
12429  {
12430  if (p.id >= static_cast<int>(al.vcount()))
12431  throw std::logic_error(
12432  "Agent's id cannot be negative above or equal to the number of agents!");
12433  }
12434  #endif
12435 
12436 }
12437 
12438 template<typename TSeq>
12439 inline bool Model<TSeq>::is_directed() const
12440 {
12441  if (population.size() == 0u)
12442  throw std::logic_error("The population hasn't been initialized.");
12443 
12444  return directed;
12445 }
12446 
12447 template<typename TSeq>
12448 inline int Model<TSeq>::today() const {
12449 
12450  if (ndays == 0)
12451  return 0;
12452 
12453  return this->current_date;
12454 }
12455 
12456 template<typename TSeq>
12457 inline void Model<TSeq>::next() {
12458 
12459  #ifdef EPI_DEBUG
12460  // Checking all the agents have proper states
12461  for (auto & p : population)
12462  {
12463  if ((p.state >= nstates) || (p.state < 0))
12464  {
12465  throw std::range_error(
12466  "The agent " + std::to_string(p.id) +
12467  " has state " + std::to_string(p.state) +
12468  " which is above the maximum state of " +
12469  std::to_string(nstates - 1) + "."
12470  );
12471  }
12472 
12473  if ((p.state_prev >= nstates) || (p.state_prev < 0))
12474  {
12475  throw std::range_error(
12476  "The agent " + std::to_string(p.id) +
12477  " has previous state " + std::to_string(p.state_prev) +
12478  " which is above the maximum state of " +
12479  std::to_string(nstates - 1) + "."
12480  );
12481  }
12482 
12483  }
12484 
12485  #endif
12486 
12487  db.record();
12488  ++this->current_date;
12489 
12490  // Advancing the progress bar
12491  if ((this->current_date >= 1) && verbose)
12492  pb.next();
12493 
12494  return ;
12495 }
12496 
12497 template<typename TSeq>
12499  epiworld_fast_uint ndays,
12500  int seed
12501 )
12502 {
12503 
12504  if (size() == 0u)
12505  throw std::logic_error("There are no agents in this model!");
12506 
12507  if (nstates == 0u)
12508  throw std::logic_error(
12509  std::string("No states registered in this model. ") +
12510  std::string("At least one state should be included. See the function -Model::add_state()-")
12511  );
12512 
12513  // Setting up the number of steps
12514  this->ndays = ndays;
12515 
12516  if (seed >= 0)
12517  engine->seed(seed);
12518 
12519  array_double_tmp.resize(std::max(
12520  size(),
12521  static_cast<size_t>(1024)
12522  ));
12523 
12524 
12525  array_virus_tmp.resize(1024);
12526 
12527  // Checking whether the proposed state in/out/removed
12528  // are valid
12529  epiworld_fast_int _init, _end, _removed;
12530  int nstate_int = static_cast<int>(nstates);
12531  for (auto & v : viruses)
12532  {
12533  v->get_state(&_init, &_end, &_removed);
12534 
12535  // Negative unspecified state
12536  if (((_init != -99) && (_init < 0)) || (_init >= nstate_int))
12537  throw std::range_error("States must be between 0 and " +
12538  std::to_string(nstates - 1));
12539 
12540  // Negative unspecified state
12541  if (((_end != -99) && (_end < 0)) || (_end >= nstate_int))
12542  throw std::range_error("States must be between 0 and " +
12543  std::to_string(nstates - 1));
12544 
12545  if (((_removed != -99) && (_removed < 0)) || (_removed >= nstate_int))
12546  throw std::range_error("States must be between 0 and " +
12547  std::to_string(nstates - 1));
12548 
12549  }
12550 
12551  for (auto & t : tools)
12552  {
12553  t->get_state(&_init, &_end);
12554 
12555  // Negative unspecified state
12556  if (((_init != -99) && (_init < 0)) || (_init >= nstate_int))
12557  throw std::range_error("States must be between 0 and " +
12558  std::to_string(nstates - 1));
12559 
12560  // Negative unspecified state
12561  if (((_end != -99) && (_end < 0)) || (_end >= nstate_int))
12562  throw std::range_error("States must be between 0 and " +
12563  std::to_string(nstates - 1));
12564 
12565  }
12566 
12567  // Starting first infection and tools
12568  reset();
12569 
12570  // Initializing the simulation
12571  chrono_start();
12572  EPIWORLD_RUN((*this))
12573  {
12574 
12575  #ifdef EPI_DEBUG
12576  db.n_transmissions_potential = 0;
12577  db.n_transmissions_today = 0;
12578  #endif
12579 
12580  // We can execute these components in whatever order the
12581  // user needs.
12582  this->update_state();
12583 
12584  // We start with the Global events
12585  this->run_globalevents();
12586 
12587  // In this case we are applying degree sequence rewiring
12588  // to change the network just a bit.
12589  this->rewire();
12590 
12591  // This locks all the changes
12592  this->next();
12593 
12594  // Mutation must happen at the very end of all
12595  this->mutate_virus();
12596 
12597  }
12598 
12599  // The last reaches the end...
12600  this->current_date--;
12601 
12602  chrono_end();
12603 
12604  return *this;
12605 
12606 }
12607 
12608 template<typename TSeq>
12610  epiworld_fast_uint ndays,
12611  epiworld_fast_uint nexperiments,
12612  int seed_,
12613  std::function<void(size_t,Model<TSeq>*)> fun,
12614  bool reset,
12615  bool verbose,
12616  #ifdef _OPENMP
12617  int nthreads
12618  #else
12619  int
12620  #endif
12621 )
12622 {
12623 
12624  if (seed_ >= 0)
12625  this->seed(seed_);
12626 
12627  // Seeds will be reproducible by default
12628  std::vector< int > seeds_n(nexperiments);
12629  for (auto & s : seeds_n)
12630  {
12631  s = static_cast<int>(
12632  std::floor(
12633  runif() * static_cast<double>(std::numeric_limits<int>::max())
12634  )
12635  );
12636  }
12637  // #endif
12638 
12639  if (verbose)
12640  {
12641  EPI_DEBUG_NOTIFY_ACTIVE()
12642  }
12643 
12644  bool old_verb = this->verbose;
12645  verbose_off();
12646 
12647  // Setting up backup
12648  if (reset)
12649  set_backup();
12650 
12651  #ifdef _OPENMP
12652 
12653  omp_set_num_threads(nthreads);
12654 
12655  // Not more than the number of experiments
12656  nthreads =
12657  static_cast<size_t>(nthreads) > nexperiments ? nexperiments : nthreads;
12658 
12659  // Generating copies of the model
12660  std::vector< Model<TSeq> * > these(
12661  std::max(nthreads - 1, 0)
12662  );
12663 
12664  #pragma omp parallel for shared(these, nthreads)
12665  for (size_t i = 0u; i < static_cast<size_t>(nthreads); ++i)
12666  {
12667 
12668  if (i == 0)
12669  continue;
12670 
12671  these[i - 1] = clone_ptr();
12672 
12673  }
12674 
12675 
12676  // Figuring out how many replicates - distribute remainder evenly
12677  std::vector< size_t > nreplicates(nthreads, 0);
12678  std::vector< size_t > nreplicates_csum(nthreads, 0);
12679 
12680  size_t base_replicates = nexperiments / nthreads;
12681  size_t remainder = nexperiments % nthreads;
12682 
12683  size_t sums = 0u;
12684  for (int i = 0; i < nthreads; ++i)
12685  {
12686  // Distribute remainder to first 'remainder' threads
12687  nreplicates[i] = base_replicates + (static_cast<size_t>(i) < remainder ? 1 : 0);
12688 
12689  // This takes the cumsum
12690  nreplicates_csum[i] = sums;
12691  sums += nreplicates[i];
12692  }
12693 
12694  Progress pb_multiple(
12695  nreplicates[0u],
12696  EPIWORLD_PROGRESS_BAR_WIDTH
12697  );
12698 
12699  if (verbose)
12700  {
12701 
12702  printf_epiworld(
12703  "Starting multiple runs (%i) using %i thread(s)\n",
12704  static_cast<int>(nexperiments),
12705  static_cast<int>(nthreads)
12706  );
12707 
12708  pb_multiple.start();
12709 
12710  }
12711 
12712  #ifdef EPI_DEBUG
12713  // Checking the initial state of all the models. Throw an
12714  // exception if they are not the same.
12715  for (size_t i = 1; i < static_cast<size_t>(std::max(nthreads - 1, 0)); ++i)
12716  {
12717 
12718  if (db != these[i]->db)
12719  {
12720  throw std::runtime_error(
12721  "The initial state of the models is not the same"
12722  );
12723  }
12724  }
12725  #endif
12726 
12727  #pragma omp parallel shared(these, nreplicates, nreplicates_csum, seeds_n) \
12728  firstprivate(nexperiments, nthreads, fun, reset, verbose, pb_multiple, ndays) \
12729  default(shared)
12730  {
12731 
12732  auto iam = omp_get_thread_num();
12733 
12734  for (size_t n = 0u; n < nreplicates[iam]; ++n)
12735  {
12736  size_t sim_id = nreplicates_csum[iam] + n;
12737  if (iam == 0)
12738  {
12739 
12740  // Checking if the user interrupted the simulation
12741  EPI_CHECK_USER_INTERRUPT(n);
12742 
12743  // Initializing the seed
12744  run(ndays, seeds_n[sim_id]);
12745 
12746  if (fun)
12747  fun(n, this);
12748 
12749  // Only the first one prints
12750  if (verbose)
12751  pb_multiple.next();
12752 
12753  } else {
12754 
12755  // Initializing the seed
12756  these[iam - 1]->run(ndays, seeds_n[sim_id]);
12757 
12758  if (fun)
12759  fun(sim_id, these[iam - 1]);
12760 
12761  }
12762 
12763  }
12764 
12765  }
12766 
12767  // Adjusting the number of replicates
12768  n_replicates += (nexperiments - nreplicates[0u]);
12769 
12770  #pragma omp parallel for shared(these)
12771  for (int i = 1; i < nthreads; ++i)
12772  {
12773  delete these[i - 1];
12774  }
12775 
12776  #else
12777  // if (reset)
12778  // set_backup();
12779 
12780  Progress pb_multiple(
12781  nexperiments,
12782  EPIWORLD_PROGRESS_BAR_WIDTH
12783  )
12784  ;
12785  if (verbose)
12786  {
12787 
12788  printf_epiworld(
12789  "Starting multiple runs (%i)\n",
12790  static_cast<int>(nexperiments)
12791  );
12792 
12793  pb_multiple.start();
12794 
12795  }
12796 
12797  for (size_t n = 0u; n < nexperiments; ++n)
12798  {
12799 
12800  // Checking if the user interrupted the simulation
12801  EPI_CHECK_USER_INTERRUPT(n);
12802 
12803  run(ndays, seeds_n[n]);
12804 
12805  if (fun)
12806  fun(n, this);
12807 
12808  if (verbose)
12809  pb_multiple.next();
12810 
12811  }
12812  #endif
12813 
12814  if (old_verb)
12815  verbose_on();
12816 
12817  return;
12818 
12819 }
12820 
12821 template<typename TSeq>
12822 inline void Model<TSeq>::update_state() {
12823 
12824  // Next state
12825  if (use_queuing)
12826  {
12827  int i = -1;
12828  for (auto & p: population)
12829  if (queue[++i] > 0)
12830  {
12831  if (state_fun[p.state])
12832  state_fun[p.state](&p, this);
12833  }
12834 
12835  }
12836  else
12837  {
12838 
12839  for (auto & p: population)
12840  if (state_fun[p.state])
12841  state_fun[p.state](&p, this);
12842 
12843  }
12844 
12845  events_run();
12846 
12847 }
12848 
12849 template<typename TSeq>
12850 inline void Model<TSeq>::mutate_virus() {
12851 
12852  // Checking if any virus has mutation
12853  size_t nmutates = 0u;
12854  for (const auto & v: viruses)
12855  if (v->virus_functions->mutation)
12856  nmutates++;
12857 
12858  if (nmutates == 0u)
12859  return;
12860 
12861  if (use_queuing)
12862  {
12863 
12864  int i = -1;
12865  for (auto & p: population)
12866  {
12867 
12868  if (queue[++i] == 0)
12869  continue;
12870 
12871  if (p.virus != nullptr)
12872  p.virus->mutate(this);
12873 
12874  }
12875 
12876  }
12877  else
12878  {
12879 
12880  for (auto & p: population)
12881  {
12882 
12883  if (p.virus != nullptr)
12884  p.virus->mutate(this);
12885 
12886  }
12887 
12888  }
12889 
12890 
12891 }
12892 
12893 template<typename TSeq>
12894 inline size_t Model<TSeq>::get_n_viruses() const {
12895  return db.size();
12896 }
12897 
12898 template<typename TSeq>
12899 inline size_t Model<TSeq>::get_n_tools() const {
12900  return tools.size();
12901 }
12902 
12903 template<typename TSeq>
12904 inline epiworld_fast_uint Model<TSeq>::get_ndays() const {
12905  return ndays;
12906 }
12907 
12908 template<typename TSeq>
12909 inline epiworld_fast_uint Model<TSeq>::get_n_replicates() const
12910 {
12911  return n_replicates;
12912 }
12913 
12914 template<typename TSeq>
12915 inline size_t Model<TSeq>::get_n_entities() const {
12916  return entities.size();
12917 }
12918 
12919 template<typename TSeq>
12920 inline void Model<TSeq>::set_ndays(epiworld_fast_uint ndays) {
12921  this->ndays = ndays;
12922 }
12923 
12924 template<typename TSeq>
12925 inline bool Model<TSeq>::get_verbose() const {
12926  return verbose;
12927 }
12928 
12929 template<typename TSeq>
12931  verbose = true;
12932  return *this;
12933 }
12934 
12935 template<typename TSeq>
12937  verbose = false;
12938  return *this;
12939 }
12940 
12941 template<typename TSeq>
12942 inline void Model<TSeq>::set_rewire_fun(
12943  std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> fun
12944  ) {
12945  rewire_fun = fun;
12946 }
12947 
12948 template<typename TSeq>
12949 inline void Model<TSeq>::set_rewire_prop(epiworld_double prop)
12950 {
12951 
12952  if (prop < 0.0)
12953  throw std::range_error("Proportions cannot be negative.");
12954 
12955  if (prop > 1.0)
12956  throw std::range_error("Proportions cannot be above 1.0.");
12957 
12958  rewire_prop = prop;
12959 }
12960 
12961 template<typename TSeq>
12962 inline epiworld_double Model<TSeq>::get_rewire_prop() const {
12963  return rewire_prop;
12964 }
12965 
12966 template<typename TSeq>
12967 inline void Model<TSeq>::rewire() {
12968 
12969  if (rewire_fun)
12970  rewire_fun(&population, this, rewire_prop);
12971 }
12972 
12973 
12974 template<typename TSeq>
12976  std::string fn_virus_info,
12977  std::string fn_virus_hist,
12978  std::string fn_tool_info,
12979  std::string fn_tool_hist,
12980  std::string fn_total_hist,
12981  std::string fn_transmission,
12982  std::string fn_transition,
12983  std::string fn_reproductive_number,
12984  std::string fn_generation_time
12985  ) const
12986 {
12987 
12988  db.write_data(
12989  fn_virus_info, fn_virus_hist,
12990  fn_tool_info, fn_tool_hist,
12991  fn_total_hist, fn_transmission, fn_transition,
12992  fn_reproductive_number, fn_generation_time
12993  );
12994 
12995 }
12996 
12997 template<typename TSeq>
12998 inline void Model<TSeq>::write_edgelist(
12999  std::string fn
13000  ) const
13001 {
13002 
13003  // Figuring out the writing sequence
13004  std::vector< const Agent<TSeq> * > wseq(size());
13005  for (const auto & p: population)
13006  wseq[p.id] = &p;
13007 
13008  std::ofstream efile(fn, std::ios_base::out);
13009  efile << "source target\n";
13010  if (this->is_directed())
13011  {
13012 
13013  for (const auto & p : wseq)
13014  {
13015 
13016  if (p->neighbors == nullptr)
13017  continue;
13018 
13019  for (auto & n : *p->neighbors)
13020  efile << p->id << " " << n << "\n";
13021  }
13022 
13023  } else {
13024 
13025  for (const auto & p : wseq)
13026  {
13027 
13028  if (p->neighbors == nullptr)
13029  continue;
13030 
13031  for (auto & n : *p->neighbors)
13032  if (static_cast<int>(p->id) <= static_cast<int>(n))
13033  efile << p->id << " " << n << "\n";
13034  }
13035 
13036  }
13037 
13038 }
13039 
13040 template<typename TSeq>
13041 inline void Model<TSeq>::write_edgelist(
13042 std::vector< int > & source,
13043 std::vector< int > & target
13044 ) const {
13045 
13046  // Figuring out the writing sequence
13047  std::vector< const Agent<TSeq> * > wseq(size());
13048  for (const auto & p: population)
13049  wseq[p.id] = &p;
13050 
13051  if (this->is_directed())
13052  {
13053 
13054  for (const auto & p : wseq)
13055  {
13056  if (p->neighbors == nullptr)
13057  continue;
13058 
13059  for (auto & n : *p->neighbors)
13060  {
13061  source.push_back(static_cast<int>(p->id));
13062  target.push_back(static_cast<int>(n));
13063  }
13064  }
13065 
13066  } else {
13067 
13068  for (const auto & p : wseq)
13069  {
13070 
13071  if (p->neighbors == nullptr)
13072  continue;
13073 
13074  for (auto & n : *p->neighbors) {
13075  if (static_cast<int>(p->id) <= static_cast<int>(n)) {
13076  source.push_back(static_cast<int>(p->id));
13077  target.push_back(static_cast<int>(n));
13078  }
13079  }
13080  }
13081 
13082  }
13083 
13084 
13085 }
13086 
13087 template<typename TSeq>
13088 inline std::map<std::string,epiworld_double> & Model<TSeq>::params()
13089 {
13090  return parameters;
13091 }
13092 
13093 template<typename TSeq>
13094 inline void Model<TSeq>::reset() {
13095 
13096  // Restablishing people
13097  pb = Progress(ndays, 80);
13098 
13099  if (population_backup.size())
13100  {
13101  population = population_backup;
13102 
13103  // Ensuring the population is poiting to the model
13104  for (auto & p : population)
13105  p.model = this;
13106 
13107  #ifdef EPI_DEBUG
13108  for (size_t i = 0; i < population.size(); ++i)
13109  {
13110 
13111  if (population[i] != (population_backup)[i])
13112  throw std::logic_error("Model::reset population doesn't match.");
13113 
13114  }
13115  #endif
13116 
13117  }
13118 
13119  for (auto & p : population)
13120  p.reset();
13121 
13122  #ifdef EPI_DEBUG
13123  for (auto & a: population)
13124  {
13125  if (a.get_state() != 0u)
13126  throw std::logic_error("Model::reset population doesn't match."
13127  "Some agents are not in the baseline state.");
13128  }
13129  #endif
13130 
13131  if (entities_backup.size())
13132  {
13133  entities = entities_backup;
13134 
13135  #ifdef EPI_DEBUG
13136  for (size_t i = 0; i < entities.size(); ++i)
13137  {
13138 
13139  if (entities[i] != (entities_backup)[i])
13140  throw std::logic_error("Model::reset entities don't match.");
13141 
13142  }
13143  #endif
13144 
13145  }
13146 
13147  for (auto & e: entities)
13148  e.reset();
13149 
13150  current_date = 0;
13151 
13152  db.reset();
13153 
13154  // This also clears the queue
13155  if (use_queuing)
13156  queue.reset();
13157 
13158  // Re distributing tools and virus
13159  dist_virus();
13160  dist_tools();
13161  dist_entities();
13162 
13163  // Distributing initial state, if specified
13164  initial_states_fun(this);
13165 
13166  // Recording the original state (at time 0) and advancing
13167  // to time 1
13168  next();
13169 
13170 
13171 }
13172 
13173 // Too big to keep here
13174 /*//////////////////////////////////////////////////////////////////////////////
13176 
13177  Start of -include/epiworld/model-meat-print.hpp-
13178 
13181 
13182 
13183 #ifndef EPIWORLD_MODEL_MEAT_PRINT_HPP
13184 #define EPIWORLD_MODEL_MEAT_PRINT_HPP
13185 
13186 template<typename TSeq>
13187 inline const Model<TSeq> & Model<TSeq>::print(bool lite) const
13188 {
13189 
13190  // Horizontal line
13191  std::string line = "";
13192  for (epiworld_fast_uint i = 0u; i < 80u; ++i)
13193  line += "_";
13194 
13195  // Prints a message if debugging is on
13196  EPI_DEBUG_NOTIFY_ACTIVE()
13197 
13198  printf_epiworld("%s\n",line.c_str());
13199 
13200  if (lite)
13201  {
13202  // Printing the name of the model
13203  printf_epiworld("%s", name.c_str());
13204 
13205  // Printing the number of agents, viruses, and tools
13206  printf_epiworld(
13207  "\nIt features %i agents, %i virus(es), and %i tool(s).\n",
13208  static_cast<int>(size()),
13209  static_cast<int>(get_n_viruses()),
13210  static_cast<int>(get_n_tools())
13211  );
13212 
13213  printf_epiworld(
13214  "The model has %i states.",
13215  static_cast<int>(nstates)
13216  );
13217 
13218  if (today() != 0)
13219  {
13220  printf_epiworld(
13221  "\nThe final distribution is: "
13222  );
13223 
13224  int nstate_int = static_cast<int>(nstates);
13225 
13226  for (int i = 0u; i < nstate_int; ++i)
13227  {
13228  printf_epiworld(
13229  "%i %s%s",
13230  static_cast<int>(db.today_total[ i ]),
13231  states_labels[i].c_str(),
13232  (
13233  i == (nstate_int - 2)
13234  ) ? ", and " : (
13235  (i == (nstate_int - 1)) ? ".\n" : ", "
13236  )
13237  );
13238  }
13239  } else {
13240  printf_epiworld(" The model hasn't been run yet.\n");
13241  }
13242 
13243  return *this;
13244  }
13245 
13246  printf_epiworld("%s\n%s\n\n",line.c_str(), "SIMULATION STUDY");
13247 
13248  printf_epiworld("Name of the model : %s\n", (this->name == "") ? std::string("(none)").c_str() : name.c_str());
13249  printf_epiworld("Population size : %i\n", static_cast<int>(size()));
13250 
13251  auto ncols = get_agents_data_ncols();
13252 
13253  if (ncols > 0)
13254  {
13255  printf_epiworld("Agents' data loaded : yes (%i columns/features)\n", static_cast<int>(ncols));
13256  }
13257  else
13258  {
13259  printf_epiworld("Agents' data : (none)\n");
13260  }
13261 
13262  printf_epiworld("Number of entities : %i\n", static_cast<int>(entities.size()));
13263  printf_epiworld("Days (duration) : %i (of %i)\n", today(), static_cast<int>(ndays));
13264  printf_epiworld("Number of viruses : %i\n", static_cast<int>(db.get_n_viruses()));
13265  if (n_replicates > 0u)
13266  {
13267  std::string abbr;
13268  epiworld_double elapsed;
13269  epiworld_double total;
13270  get_elapsed("auto", &elapsed, &total, &abbr, false);
13271  printf_epiworld("Last run elapsed t : %.2f%s\n", elapsed, abbr.c_str());
13272  if (n_replicates > 1u)
13273  {
13274  printf_epiworld("Total elapsed t : %.2f%s (%i runs)\n", total, abbr.c_str(), static_cast<int>(n_replicates));
13275  }
13276 
13277  // Elapsed time in speed
13278  get_elapsed("microseconds", &elapsed, &total, &abbr, false);
13279  printf_epiworld("Last run speed : %.2f million agents x day / second\n",
13280  static_cast<double>(this->size()) *
13281  static_cast<double>(this->get_ndays()) /
13282  static_cast<double>(elapsed)
13283  );
13284  if (n_replicates > 1u)
13285  {
13286  printf_epiworld("Average run speed : %.2f million agents x day / second\n",
13287  static_cast<double>(this->size()) *
13288  static_cast<double>(this->get_ndays()) *
13289  static_cast<double>(n_replicates) /
13290  static_cast<double>(total)
13291  );
13292  }
13293 
13294  } else {
13295  printf_epiworld("Last run elapsed t : -\n");
13296  }
13297 
13298 
13299  if (rewire_fun)
13300  {
13301  printf_epiworld("Rewiring : on (%.2f)\n\n", rewire_prop);
13302  } else {
13303  printf_epiworld("Rewiring : off\n\n");
13304  }
13305 
13306  // Printing Global events
13307  printf_epiworld("Global events:\n");
13308  for (auto & a : globalevents)
13309  {
13310  if (a.get_day() < 0)
13311  {
13312  printf_epiworld(" - %s (runs daily)\n", a.get_name().c_str());
13313  } else {
13314  printf_epiworld(" - %s (day %i)\n", a.get_name().c_str(), a.get_day());
13315  }
13316  }
13317 
13318  if (globalevents.size() == 0u)
13319  {
13320  printf_epiworld(" (none)\n");
13321  }
13322 
13323  printf_epiworld("\nVirus(es):\n");
13324  size_t n_viruses_model = viruses.size();
13325  for (size_t i = 0u; i < n_viruses_model; ++i)
13326  {
13327 
13328 
13329  const auto & virus = viruses[i];
13330  if ((n_viruses_model > 10) && (i >= 10))
13331  {
13332  printf_epiworld(" ...and %i more viruses...\n",
13333  static_cast<int>(n_viruses_model) -
13334  static_cast<int>(i)
13335  );
13336  break;
13337  }
13338 
13339  if (i < n_viruses_model)
13340  {
13341 
13342  printf_epiworld(
13343  " - %s\n",
13344  virus->get_name().c_str()
13345  );
13346 
13347  } else {
13348 
13349  printf_epiworld(
13350  " - %s (originated in the model...)\n",
13351  virus->get_name().c_str()
13352  );
13353 
13354  }
13355 
13356  }
13357 
13358  auto nvariants = db.get_n_viruses() - n_viruses_model;
13359  if (nvariants > 0)
13360  {
13361 
13362  printf_epiworld(" ...and %i more variants...\n", static_cast<int>(nvariants));
13363 
13364  }
13365 
13366  if (viruses.size() == 0u)
13367  {
13368  printf_epiworld(" (none)\n");
13369  }
13370 
13371  printf_epiworld("\nTool(s):\n");
13372  size_t n_tools_model = tools.size();
13373  for (size_t i = 0u; i < tools.size(); ++i)
13374  {
13375  const auto & tool = tools[i];
13376 
13377  if ((n_tools_model > 10) && (i >= 10))
13378  {
13379  printf_epiworld(
13380  " ...and %i more tools...\n",
13381  static_cast<int>(n_tools_model) - static_cast<int>(i)
13382  );
13383  break;
13384  }
13385 
13386  if (i < n_tools_model)
13387  {
13388  printf_epiworld(
13389  " - %s\n",
13390  tool->get_name().c_str()
13391  );
13392 
13393 
13394  } else {
13395 
13396  printf_epiworld(
13397  " - %s (originated in the model...)\n",
13398  tool->get_name().c_str()
13399  );
13400 
13401  }
13402 
13403 
13404  }
13405 
13406  if (tools.size() == 0u)
13407  {
13408  printf_epiworld(" (none)\n");
13409  }
13410 
13411  // Information about the parameters included
13412  printf_epiworld("\nModel parameters:\n");
13413  epiworld_fast_uint nchar = 0u;
13414  for (auto & p : parameters)
13415  if (p.first.length() > nchar)
13416  nchar = p.first.length();
13417 
13418  std::string fmt = " - %-" + std::to_string(nchar + 1) + "s: ";
13419  for (auto & p : parameters)
13420  {
13421  std::string fmt_tmp = fmt;
13422  if (std::fabs(p.second) < 0.0001)
13423  fmt_tmp += "%.1e\n";
13424  else
13425  fmt_tmp += "%.4f\n";
13426 
13427  printf_epiworld(
13428  fmt_tmp.c_str(),
13429  p.first.c_str(),
13430  p.second
13431  );
13432 
13433  }
13434 
13435  if (parameters.size() == 0u)
13436  {
13437  printf_epiworld(" (none)\n");
13438  }
13439 
13440  nchar = 0u;
13441  for (auto & p : states_labels)
13442  if (p.length() > nchar)
13443  nchar = p.length();
13444 
13445 
13446 
13447  if (today() != 0)
13448  {
13449  fmt =
13450  std::string(" - (%") +
13451  std::to_string(std::to_string(nstates).length()) +
13452  std::string("d) %-") + std::to_string(nchar) +
13453  std::string("s : %") +
13454  std::to_string(std::to_string(size()).length()) +
13455  std::string("i -> %i\n");
13456  } else {
13457  fmt =
13458  std::string(" - (%") +
13459  std::to_string(std::to_string(nstates).length()) +
13460  std::string("d) %-") + std::to_string(nchar) +
13461  std::string("s : %i\n");
13462  }
13463 
13464  if (today() != 0)
13465  {
13466  printf_epiworld("\nDistribution of the population at time %i:\n", today());
13467  for (size_t s = 0u; s < nstates; ++s)
13468  {
13469 
13470  printf_epiworld(
13471  fmt.c_str(),
13472  s,
13473  states_labels[s].c_str(),
13474  db.hist_total_counts[s],
13475  db.today_total[ s ]
13476  );
13477 
13478  }
13479  }
13480 
13481  if (today() != 0)
13482  (void) db.get_transition_probability(true);
13483 
13484  return *this;
13485 
13486 }
13487 
13488 #endif
13489 /*//////////////////////////////////////////////////////////////////////////////
13491 
13492  End of -include/epiworld/model-meat-print.hpp-
13493 
13496 
13497 
13498 
13499 
13500 template<typename TSeq>
13501 inline void Model<TSeq>::add_state(
13502  std::string lab,
13503  UpdateFun<TSeq> fun
13504 )
13505 {
13506 
13507  // Checking it doesn't match
13508  for (auto & s : states_labels)
13509  if (s == lab)
13510  throw std::logic_error("state \"" + s + "\" already registered.");
13511 
13512  states_labels.push_back(lab);
13513  state_fun.push_back(fun);
13514  nstates++;
13515 
13516 }
13517 
13518 
13519 template<typename TSeq>
13520 inline const std::vector< std::string > &
13521 Model<TSeq>::get_states() const
13522 {
13523  return states_labels;
13524 }
13525 
13526 template<typename TSeq>
13527 inline size_t Model<TSeq>::get_n_states() const
13528 {
13529  return nstates;
13530 }
13531 
13532 template<typename TSeq>
13533 inline const std::vector< UpdateFun<TSeq> > &
13534 Model<TSeq>::get_state_fun() const
13535 {
13536  return state_fun;
13537 }
13538 
13539 template<typename TSeq>
13540 inline void Model<TSeq>::print_state_codes() const
13541 {
13542 
13543  // Horizontal line
13544  std::string line = "";
13545  for (epiworld_fast_uint i = 0u; i < 80u; ++i)
13546  line += "_";
13547 
13548  printf_epiworld("\n%s\nstates CODES\n\n", line.c_str());
13549 
13550  epiworld_fast_uint nchar = 0u;
13551  for (auto & p : states_labels)
13552  if (p.length() > nchar)
13553  nchar = p.length();
13554 
13555  std::string fmt = " %2i = %-" + std::to_string(nchar + 1 + 4) + "s\n";
13556  for (epiworld_fast_uint i = 0u; i < nstates; ++i)
13557  {
13558 
13559  printf_epiworld(
13560  fmt.c_str(),
13561  i,
13562  (states_labels[i] + " (S)").c_str()
13563  );
13564 
13565  }
13566 
13567 }
13568 
13569 
13570 
13571 template<typename TSeq>
13572 inline epiworld_double Model<TSeq>::add_param(
13573  epiworld_double initial_value,
13574  std::string pname,
13575  bool overwrite
13576  ) {
13577 
13578  if (parameters.find(pname) == parameters.end())
13579  parameters[pname] = initial_value;
13580  else if (!overwrite)
13581  throw std::logic_error("The parameter " + pname + " already exists.");
13582  else
13583  parameters[pname] = initial_value;
13584 
13585  return initial_value;
13586 
13587 }
13588 
13589 template<typename TSeq>
13590 inline Model<TSeq> & Model<TSeq>::read_params(std::string fn, bool overwrite)
13591 {
13592 
13593  auto params_map = read_yaml<epiworld_double>(fn);
13594 
13595  for (auto & p : params_map)
13596  add_param(p.second, p.first, overwrite);
13597 
13598  return *this;
13599 
13600 }
13601 
13602 template<typename TSeq>
13603 inline epiworld_double Model<TSeq>::get_param(std::string pname)
13604 {
13605  if (parameters.find(pname) == parameters.end())
13606  throw std::logic_error("The parameter " + pname + " does not exists.");
13607 
13608  return parameters[pname];
13609 }
13610 
13611 template<typename TSeq>
13612 inline void Model<TSeq>::set_param(std::string pname, epiworld_double value)
13613 {
13614  if (parameters.find(pname) == parameters.end())
13615  throw std::logic_error("The parameter " + pname + " does not exists.");
13616 
13617  parameters[pname] = value;
13618 
13619  return;
13620 
13621 }
13622 
13623 // // Same as before but using the size_t method
13624 // template<typename TSeq>
13625 // inline void Model<TSeq>::set_param(size_t k, epiworld_double value)
13626 // {
13627 // if (k >= parameters.size())
13628 // throw std::logic_error("The parameter index " + std::to_string(k) + " does not exists.");
13629 
13630 // // Access the k-th element of the std::unordered_map parameters
13631 
13632 
13633 // *(parameters.begin() + k) = value;
13634 
13635 // return;
13636 // }
13637 
13638 template<typename TSeq>
13639 inline epiworld_double Model<TSeq>::par(std::string pname) const
13640 {
13641  const auto iter = parameters.find(pname);
13642  if (iter == parameters.end())
13643  throw std::logic_error("The parameter " + pname + " does not exists.");
13644  return iter->second;
13645 }
13646 
13647 #define DURCAST(tunit,txtunit) {\
13648  elapsed = std::chrono::duration_cast<std::chrono:: tunit>(\
13649  time_end - time_start).count(); \
13650  elapsed_total = std::chrono::duration_cast<std::chrono:: tunit>(time_elapsed).count(); \
13651  abbr_unit = txtunit;}
13652 
13653 template<typename TSeq>
13654 inline void Model<TSeq>::get_elapsed(
13655  std::string unit,
13656  epiworld_double * last_elapsed,
13657  epiworld_double * total_elapsed,
13658  std::string * unit_abbr,
13659  bool print
13660 ) const {
13661 
13662  // Preparing the result
13663  epiworld_double elapsed, elapsed_total;
13664  std::string abbr_unit;
13665 
13666  // Figuring out the length
13667  if (unit == "auto")
13668  {
13669 
13670  size_t tlength = std::to_string(
13671  static_cast<int>(floor(time_elapsed.count()))
13672  ).length();
13673 
13674  if (tlength <= 1)
13675  unit = "nanoseconds";
13676  else if (tlength <= 3)
13677  unit = "microseconds";
13678  else if (tlength <= 6)
13679  unit = "milliseconds";
13680  else if (tlength <= 8)
13681  unit = "seconds";
13682  else if (tlength <= 9)
13683  unit = "minutes";
13684  else
13685  unit = "hours";
13686 
13687  }
13688 
13689  if (unit == "nanoseconds") DURCAST(nanoseconds,"ns")
13690  else if (unit == "microseconds") DURCAST(microseconds,"\xC2\xB5s")
13691  else if (unit == "milliseconds") DURCAST(milliseconds,"ms")
13692  else if (unit == "seconds") DURCAST(seconds,"s")
13693  else if (unit == "minutes") DURCAST(minutes,"m")
13694  else if (unit == "hours") DURCAST(hours,"h")
13695  else
13696  throw std::range_error("The time unit " + unit + " is not supported.");
13697 
13698 
13699  if (last_elapsed != nullptr)
13700  *last_elapsed = elapsed;
13701  if (total_elapsed != nullptr)
13702  *total_elapsed = elapsed_total;
13703  if (unit_abbr != nullptr)
13704  *unit_abbr = abbr_unit;
13705 
13706  if (!print)
13707  return;
13708 
13709  if (n_replicates > 1u)
13710  {
13711  printf_epiworld("last run elapsed time : %.2f%s\n",
13712  elapsed, abbr_unit.c_str());
13713  printf_epiworld("total elapsed time : %.2f%s\n",
13714  elapsed_total, abbr_unit.c_str());
13715  printf_epiworld("total runs : %i\n",
13716  static_cast<int>(n_replicates));
13717  printf_epiworld("mean run elapsed time : %.2f%s\n",
13718  elapsed_total/static_cast<epiworld_double>(n_replicates), abbr_unit.c_str());
13719 
13720  } else {
13721  printf_epiworld("last run elapsed time : %.2f%s.\n", elapsed, abbr_unit.c_str());
13722  }
13723 }
13724 
13725 template<typename TSeq>
13726 inline void Model<TSeq>::set_user_data(std::vector< std::string > names)
13727 {
13728  db.set_user_data(names);
13729 }
13730 
13731 template<typename TSeq>
13732 inline void Model<TSeq>::add_user_data(epiworld_fast_uint j, epiworld_double x)
13733 {
13734  db.add_user_data(j, x);
13735 }
13736 
13737 template<typename TSeq>
13738 inline void Model<TSeq>::add_user_data(std::vector<epiworld_double> x)
13739 {
13740  db.add_user_data(x);
13741 }
13742 
13743 template<typename TSeq>
13744 inline UserData<TSeq> & Model<TSeq>::get_user_data()
13745 {
13746  return db.get_user_data();
13747 }
13748 
13749 template<typename TSeq>
13750 inline void Model<TSeq>::add_globalevent(
13751  std::function<void(Model<TSeq>*)> fun,
13752  std::string name,
13753  int date
13754 )
13755 {
13756 
13757  globalevents.push_back(
13758  GlobalEvent<TSeq>(
13759  fun,
13760  name,
13761  date
13762  )
13763  );
13764 
13765 }
13766 
13767 template<typename TSeq>
13768 inline void Model<TSeq>::add_globalevent(
13769  GlobalEvent<TSeq> action
13770 )
13771 {
13772  globalevents.push_back(action);
13773 }
13774 
13775 template<typename TSeq>
13776 GlobalEvent<TSeq> & Model<TSeq>::get_globalevent(
13777  std::string name
13778 )
13779 {
13780 
13781  for (auto & a : globalevents)
13782  if (a.name == name)
13783  return a;
13784 
13785  throw std::logic_error("The global action " + name + " was not found.");
13786 
13787 }
13788 
13789 template<typename TSeq>
13790 GlobalEvent<TSeq> & Model<TSeq>::get_globalevent(
13791  size_t index
13792 )
13793 {
13794 
13795  if (index >= globalevents.size())
13796  throw std::range_error("The index " + std::to_string(index) + " is out of range.");
13797 
13798  return globalevents[index];
13799 
13800 }
13801 
13802 // Remove implementation
13803 template<typename TSeq>
13804 inline void Model<TSeq>::rm_globalevent(
13805  std::string name
13806 )
13807 {
13808 
13809  for (auto it = globalevents.begin(); it != globalevents.end(); ++it)
13810  {
13811  if (it->get_name() == name)
13812  {
13813  globalevents.erase(it);
13814  return;
13815  }
13816  }
13817 
13818  throw std::logic_error("The global action " + name + " was not found.");
13819 
13820 }
13821 
13822 // Same as above, but the index implementation
13823 template<typename TSeq>
13824 inline void Model<TSeq>::rm_globalevent(
13825  size_t index
13826 )
13827 {
13828 
13829  if (index >= globalevents.size())
13830  throw std::range_error("The index " + std::to_string(index) + " is out of range.");
13831 
13832  globalevents.erase(globalevents.begin() + index);
13833 
13834 }
13835 
13836 template<typename TSeq>
13837 inline void Model<TSeq>::run_globalevents()
13838 {
13839 
13840  for (auto & action: globalevents)
13841  {
13842  action(this, today());
13843  events_run();
13844  }
13845 
13846 }
13847 
13848 template<typename TSeq>
13849 inline void Model<TSeq>::queuing_on()
13850 {
13851  use_queuing = true;
13852 }
13853 
13854 template<typename TSeq>
13855 inline Model<TSeq> & Model<TSeq>::queuing_off()
13856 {
13857  use_queuing = false;
13858  return *this;
13859 }
13860 
13861 template<typename TSeq>
13862 inline bool Model<TSeq>::is_queuing_on() const
13863 {
13864  return use_queuing;
13865 }
13866 
13867 template<typename TSeq>
13868 inline Queue<TSeq> & Model<TSeq>::get_queue()
13869 {
13870  return queue;
13871 }
13872 
13873 template<typename TSeq>
13874 inline const std::vector< VirusPtr<TSeq> > & Model<TSeq>::get_viruses() const
13875 {
13876  return viruses;
13877 }
13878 
13879 template<typename TSeq>
13880 const std::vector< ToolPtr<TSeq> > & Model<TSeq>::get_tools() const
13881 {
13882  return tools;
13883 }
13884 
13885 template<typename TSeq>
13886 inline Virus<TSeq> & Model<TSeq>::get_virus(size_t id)
13887 {
13888 
13889  if (viruses.size() <= id)
13890  throw std::length_error("The specified id for the virus is out of range");
13891 
13892  return *viruses[id];
13893 
13894 }
13895 
13896 template<typename TSeq>
13897 inline Tool<TSeq> & Model<TSeq>::get_tool(size_t id)
13898 {
13899 
13900  if (tools.size() <= id)
13901  throw std::length_error("The specified id for the tools is out of range");
13902 
13903  return *tools[id];
13904 
13905 }
13906 
13907 
13908 template<typename TSeq>
13909 inline void Model<TSeq>::set_agents_data(double * data_, size_t ncols_)
13910 {
13911  agents_data = data_;
13912  agents_data_ncols = ncols_;
13913 }
13914 
13915 template<typename TSeq>
13916 inline double * Model<TSeq>::get_agents_data() {
13917  return this->agents_data;
13918 }
13919 
13920 template<typename TSeq>
13921 inline size_t Model<TSeq>::get_agents_data_ncols() const {
13922  return this->agents_data_ncols;
13923 }
13924 
13925 
13926 template<typename TSeq>
13927 inline void Model<TSeq>::set_name(std::string name)
13928 {
13929  this->name = name;
13930 }
13931 
13932 template<typename TSeq>
13933 inline std::string Model<TSeq>::get_name() const
13934 {
13935  return this->name;
13936 }
13937 
13938 #define VECT_MATCH(a, b, c) \
13939  EPI_DEBUG_FAIL_AT_TRUE(a.size() != b.size(), c) \
13940  for (size_t __i = 0u; __i < a.size(); ++__i) \
13941  {\
13942  EPI_DEBUG_FAIL_AT_TRUE(a[__i] != b[__i], c) \
13943  }
13944 
13945 template<typename TSeq>
13946 inline bool Model<TSeq>::operator==(const Model<TSeq> & other) const
13947 {
13948  EPI_DEBUG_FAIL_AT_TRUE(name != other.name, "names don't match")
13949  EPI_DEBUG_FAIL_AT_TRUE(db != other.db, "database don't match")
13950 
13951  VECT_MATCH(population, other.population, "population doesn't match")
13952 
13953  EPI_DEBUG_FAIL_AT_TRUE(
13954  using_backup != other.using_backup,
13955  "Model:: using_backup don't match"
13956  )
13957 
13958  if ((population_backup.size() != 0) & (other.population_backup.size() != 0))
13959  {
13960 
13961  // False is population_backup.size() != other.population_backup.size()
13962  if (population_backup.size() != other.population_backup.size())
13963  return false;
13964 
13965  for (size_t i = 0u; i < population_backup.size(); ++i)
13966  {
13967  if (population_backup[i] != other.population_backup[i])
13968  return false;
13969  }
13970 
13971  } else if ((population_backup.size() == 0) & (other.population_backup.size() != 0)) {
13972  return false;
13973  } else if ((population_backup.size() != 0) & (other.population_backup.size() == 0))
13974  {
13975  return false;
13976  }
13977 
13978  EPI_DEBUG_FAIL_AT_TRUE(
13979  agents_data != other.agents_data,
13980  "Model:: agents_data don't match"
13981  )
13982 
13983  EPI_DEBUG_FAIL_AT_TRUE(
13984  agents_data_ncols != other.agents_data_ncols,
13985  "Model:: agents_data_ncols don't match"
13986  )
13987 
13988  EPI_DEBUG_FAIL_AT_TRUE(
13989  directed != other.directed,
13990  "Model:: directed don't match"
13991  )
13992 
13993  // Viruses -----------------------------------------------------------------
13994  EPI_DEBUG_FAIL_AT_TRUE(
13995  viruses.size() != other.viruses.size(),
13996  "Model:: viruses.size() don't match"
13997  )
13998 
13999  for (size_t i = 0u; i < viruses.size(); ++i)
14000  {
14001  EPI_DEBUG_FAIL_AT_TRUE(
14002  *viruses[i] != *other.viruses[i],
14003  "Model:: *viruses[i] don't match"
14004  )
14005 
14006  }
14007 
14008  // Tools -------------------------------------------------------------------
14009  EPI_DEBUG_FAIL_AT_TRUE(
14010  tools.size() != other.tools.size(),
14011  "Model:: tools.size() don't match"
14012  )
14013 
14014  for (size_t i = 0u; i < tools.size(); ++i)
14015  {
14016  EPI_DEBUG_FAIL_AT_TRUE(
14017  *tools[i] != *other.tools[i],
14018  "Model:: *tools[i] don't match"
14019  )
14020 
14021  }
14022 
14023  VECT_MATCH(
14024  entities,
14025  other.entities,
14026  "entities don't match"
14027  )
14028 
14029  if ((entities_backup.size() != 0) & (other.entities_backup.size() != 0))
14030  {
14031 
14032  for (size_t i = 0u; i < entities_backup.size(); ++i)
14033  {
14034 
14035  EPI_DEBUG_FAIL_AT_TRUE(
14036  entities_backup[i] != other.entities_backup[i],
14037  "Model:: entities_backup[i] don't match"
14038  )
14039 
14040  }
14041 
14042  } else if ((entities_backup.size() == 0) & (other.entities_backup.size() != 0)) {
14043  EPI_DEBUG_FAIL_AT_TRUE(true, "entities_backup don't match")
14044  } else if ((entities_backup.size() != 0) & (other.entities_backup.size() == 0))
14045  {
14046  EPI_DEBUG_FAIL_AT_TRUE(true, "entities_backup don't match")
14047  }
14048 
14049  EPI_DEBUG_FAIL_AT_TRUE(
14050  rewire_prop != other.rewire_prop,
14051  "Model:: rewire_prop don't match"
14052  )
14053 
14054  EPI_DEBUG_FAIL_AT_TRUE(
14055  parameters.size() != other.parameters.size(),
14056  "Model:: () don't match"
14057  )
14058 
14059  EPI_DEBUG_FAIL_AT_TRUE(
14060  parameters != other.parameters,
14061  "Model:: parameters don't match"
14062  )
14063 
14064  EPI_DEBUG_FAIL_AT_TRUE(
14065  ndays != other.ndays,
14066  "Model:: ndays don't match"
14067  )
14068 
14069  VECT_MATCH(
14070  states_labels,
14071  other.states_labels,
14072  "state labels don't match"
14073  )
14074 
14075  EPI_DEBUG_FAIL_AT_TRUE(
14076  nstates != other.nstates,
14077  "Model:: nstates don't match"
14078  )
14079 
14080  EPI_DEBUG_FAIL_AT_TRUE(
14081  verbose != other.verbose,
14082  "Model:: verbose don't match"
14083  )
14084 
14085  EPI_DEBUG_FAIL_AT_TRUE(
14086  current_date != other.current_date,
14087  "Model:: current_date don't match"
14088  )
14089 
14090  VECT_MATCH(globalevents, other.globalevents, "global action don't match");
14091 
14092  EPI_DEBUG_FAIL_AT_TRUE(
14093  queue != other.queue,
14094  "Model:: queue don't match"
14095  )
14096 
14097 
14098  EPI_DEBUG_FAIL_AT_TRUE(
14099  use_queuing != other.use_queuing,
14100  "Model:: use_queuing don't match"
14101  )
14102 
14103  return true;
14104 
14105 }
14106 
14107 template<typename TSeq>
14108 inline void Model<TSeq>::draw(
14109  DiagramType diagram_type,
14110  const std::string & fn_output,
14111  bool self
14112 ) {
14113 
14114  ModelDiagram diagram;
14115 
14116  diagram.draw_from_data(
14117  diagram_type,
14118  this->get_states(),
14119  this->get_db().get_transition_probability(false),
14120  fn_output,
14121  self
14122  );
14123 
14124  return;
14125 
14126 }
14127 
14128 #undef VECT_MATCH
14129 #undef DURCAST
14130 #undef CASES_PAR
14131 #undef CASE_PAR
14132 #undef CHECK_INIT
14133 #endif
14134 /*//////////////////////////////////////////////////////////////////////////////
14136 
14137  End of -include/epiworld/model-meat.hpp-
14138 
14141 
14142 
14143 
14144 /*//////////////////////////////////////////////////////////////////////////////
14146 
14147  Start of -include/epiworld/viruses-bones.hpp-
14148 
14151 
14152 
14153 #ifndef EPIWORLD_VIRUSES_BONES_HPP
14154 #define EPIWORLD_VIRUSES_BONES_HPP
14155 
14156 template<typename TSeq>
14157 class Virus;
14158 
14159 template<typename TSeq>
14160 class Agent;
14161 
14167 template<typename TSeq>
14168 class Viruses {
14169  friend class Virus<TSeq>;
14170  friend class Agent<TSeq>;
14171 private:
14172  std::vector< VirusPtr<TSeq> > * dat;
14173  const epiworld_fast_uint * n_viruses;
14174 
14175 public:
14176 
14177  Viruses() = delete;
14178  Viruses(Agent<TSeq> & p) : dat(&p.viruses), n_viruses(&p.n_viruses) {};
14179 
14180  typename std::vector< VirusPtr<TSeq> >::iterator begin();
14181  typename std::vector< VirusPtr<TSeq> >::iterator end();
14182 
14183  VirusPtr<TSeq> & operator()(size_t i);
14184  VirusPtr<TSeq> & operator[](size_t i);
14185 
14186  size_t size() const noexcept;
14187 
14188  void print() const noexcept;
14189 
14190 };
14191 
14192 template<typename TSeq>
14193 inline typename std::vector< VirusPtr<TSeq> >::iterator Viruses<TSeq>::begin()
14194 {
14195 
14196  if (*n_viruses == 0u)
14197  return dat->end();
14198 
14199  return dat->begin();
14200 }
14201 
14202 template<typename TSeq>
14203 inline typename std::vector< VirusPtr<TSeq> >::iterator Viruses<TSeq>::end()
14204 {
14205 
14206  #ifdef EPI_DEBUG
14207  if (dat->size() < *n_viruses)
14208  throw EPI_DEBUG_ERROR(std::logic_error, "Viruses:: The end of the virus is out of range");
14209  #endif
14210 
14211  return begin() + *n_viruses;
14212 }
14213 
14214 template<typename TSeq>
14215 inline VirusPtr<TSeq> & Viruses<TSeq>::operator()(size_t i)
14216 {
14217 
14218  if (i >= *n_viruses)
14219  throw std::range_error("Virus index out of range.");
14220 
14221  return dat->operator[](i);
14222 
14223 }
14224 
14225 template<typename TSeq>
14226 inline VirusPtr<TSeq> & Viruses<TSeq>::operator[](size_t i)
14227 {
14228 
14229  return dat->operator[](i);
14230 
14231 }
14232 
14233 template<typename TSeq>
14234 inline size_t Viruses<TSeq>::size() const noexcept
14235 {
14236  return *n_viruses;
14237 }
14238 
14239 template<typename TSeq>
14240 inline void Viruses<TSeq>::print() const noexcept
14241 {
14242 
14243  if (*n_viruses == 0u)
14244  {
14245  printf_epiworld("List of viruses (none)\n");
14246  return;
14247  }
14248 
14249  printf_epiworld("List of viruses (%i): ", *n_viruses);
14250 
14251  // Printing the name of each virus separated by a comma
14252  for (size_t i = 0u; i < *n_viruses; ++i)
14253  {
14254  if (i == *n_viruses - 1u)
14255  {
14256  printf_epiworld("%s", dat->operator[](i)->get_name().c_str());
14257  } else
14258  {
14259  printf_epiworld("%s, ", dat->operator[](i)->get_name().c_str());
14260  }
14261  }
14262 
14263  printf_epiworld("\n");
14264 
14265 }
14266 
14272 template<typename TSeq>
14273 class Viruses_const {
14274  friend class Virus<TSeq>;
14275  friend class Agent<TSeq>;
14276 private:
14277  const std::vector< VirusPtr<TSeq> > * dat;
14278  const epiworld_fast_uint * n_viruses;
14279 
14280 public:
14281 
14282  Viruses_const() = delete;
14283  Viruses_const(const Agent<TSeq> & p) : dat(&p.viruses), n_viruses(&p.n_viruses) {};
14284 
14285  typename std::vector< VirusPtr<TSeq> >::const_iterator begin() const;
14286  typename std::vector< VirusPtr<TSeq> >::const_iterator end() const;
14287 
14288  const VirusPtr<TSeq> & operator()(size_t i);
14289  const VirusPtr<TSeq> & operator[](size_t i);
14290 
14291  size_t size() const noexcept;
14292 
14293  void print() const noexcept;
14294 
14295 };
14296 
14297 template<typename TSeq>
14298 inline typename std::vector< VirusPtr<TSeq> >::const_iterator Viruses_const<TSeq>::begin() const {
14299 
14300  if (*n_viruses == 0u)
14301  return dat->end();
14302 
14303  return dat->begin();
14304 }
14305 
14306 template<typename TSeq>
14307 inline typename std::vector< VirusPtr<TSeq> >::const_iterator Viruses_const<TSeq>::end() const {
14308 
14309  #ifdef EPI_DEBUG
14310  if (dat->size() < *n_viruses)
14311  throw EPI_DEBUG_ERROR(std::logic_error, "Viruses_const:: The end of the virus is out of range");
14312  #endif
14313  return begin() + *n_viruses;
14314 }
14315 
14316 template<typename TSeq>
14317 inline const VirusPtr<TSeq> & Viruses_const<TSeq>::operator()(size_t i)
14318 {
14319 
14320  if (i >= *n_viruses)
14321  throw std::range_error("Virus index out of range.");
14322 
14323  return dat->operator[](i);
14324 
14325 }
14326 
14327 template<typename TSeq>
14328 inline const VirusPtr<TSeq> & Viruses_const<TSeq>::operator[](size_t i)
14329 {
14330 
14331  return dat->operator[](i);
14332 
14333 }
14334 
14335 template<typename TSeq>
14336 inline size_t Viruses_const<TSeq>::size() const noexcept
14337 {
14338  return *n_viruses;
14339 }
14340 
14341 template<typename TSeq>
14342 inline void Viruses_const<TSeq>::print() const noexcept
14343 {
14344 
14345  if (*n_viruses == 0u)
14346  {
14347  printf_epiworld("List of viruses (none)\n");
14348  return;
14349  }
14350 
14351  printf_epiworld("List of viruses (%i): ", *n_viruses);
14352 
14353  // Printing the name of each virus separated by a comma
14354  for (size_t i = 0u; i < *n_viruses; ++i)
14355  {
14356  if (i == *n_viruses - 1u)
14357  {
14358  printf_epiworld("%s", dat->operator[](i)->get_name().c_str());
14359  } else
14360  {
14361  printf_epiworld("%s, ", dat->operator[](i)->get_name().c_str());
14362  }
14363  }
14364 
14365  printf_epiworld("\n");
14366 
14367 }
14368 
14369 
14370 #endif
14371 /*//////////////////////////////////////////////////////////////////////////////
14373 
14374  End of -include/epiworld/viruses-bones.hpp-
14375 
14378 
14379 
14380 
14381 /*//////////////////////////////////////////////////////////////////////////////
14383 
14384  Start of -include/epiworld/virus-bones.hpp-
14385 
14388 
14389 
14390 #ifndef EPIWORLD_VIRUS_HPP
14391 #define EPIWORLD_VIRUS_HPP
14392 
14393 template<typename TSeq>
14394 class Agent;
14395 
14396 template<typename TSeq>
14397 class Virus;
14398 
14399 template<typename TSeq>
14400 class Model;
14401 
14402 template<typename TSeq>
14403 class VirusFunctions {
14404 public:
14405  MutFun<TSeq> mutation = nullptr;
14406  PostRecoveryFun<TSeq> post_recovery = nullptr;
14407  VirusFun<TSeq> probability_of_infecting = nullptr;
14408  VirusFun<TSeq> probability_of_recovery = nullptr;
14409  VirusFun<TSeq> probability_of_death = nullptr;
14410  VirusFun<TSeq> incubation = nullptr;
14411 
14412  // Information about how distribution works
14413  VirusToAgentFun<TSeq> dist = nullptr;
14414 
14415  VirusFunctions() = default;
14416 
14417 };
14418 
14429 template<typename TSeq>
14430 class Virus {
14431  friend class Agent<TSeq>;
14432  friend class Model<TSeq>;
14433  friend class DataBase<TSeq>;
14434  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
14435  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
14436 private:
14437 
14438  Agent<TSeq> * agent = nullptr;
14439 
14440  EPI_TYPENAME_TRAITS(TSeq, int) baseline_sequence =
14441  EPI_TYPENAME_TRAITS(TSeq, int)();
14442 
14443  std::string virus_name = "unknown virus";
14444  int date = -99;
14445  int id = -99;
14446  epiworld_fast_int state_init = -99; ///< Change of state when added to agent.
14447  epiworld_fast_int state_post = -99; ///< Change of state when removed from agent.
14448  epiworld_fast_int state_removed = -99; ///< Change of state when agent is removed
14449 
14450  epiworld_fast_int queue_init = Queue<TSeq>::Everyone; ///< Change of state when added to agent.
14451  epiworld_fast_int queue_post = -Queue<TSeq>::Everyone; ///< Change of state when removed from agent.
14452  epiworld_fast_int queue_removed = -Queue<TSeq>::Everyone; ///< Change of state when agent is removed
14453 
14454  std::shared_ptr< VirusFunctions<TSeq> > virus_functions =
14455  std::make_shared< VirusFunctions<TSeq> >();
14456 
14457 public:
14458 
14459  #ifdef EPI_DEBUG_VIRUS
14460  static std::atomic<int> counter_construct; // Default and parameterized constructors
14461  static std::atomic<int> counter_copy_construct; // Copy constructor
14462  static std::atomic<int> counter_move_construct; // Move constructor
14463  static std::atomic<int> counter_copy_assign; // Copy assignment
14464  static std::atomic<int> counter_move_assign; // Move assignment
14465  static std::atomic<int> counter_destruct; // Destructor
14466  #endif
14467 
14468  Virus();
14469 
14470  Virus(std::string name = "unknown virus");
14471 
14472  Virus(
14473  std::string name,
14474  epiworld_double prevalence,
14475  bool as_proportion
14476  );
14477 
14478  #ifdef EPI_DEBUG_VIRUS
14479 
14480  // Copy and move operations for debugging
14481  Virus(const Virus<TSeq>& other); // Copy constructor
14482  Virus(Virus<TSeq>&& other) noexcept; // Move constructor
14483  Virus<TSeq>& operator=(const Virus<TSeq>& other); // Copy assignment
14484  Virus<TSeq>& operator=(Virus<TSeq>&& other) noexcept; // Move assignment
14485 
14486  ~Virus();
14487  #endif
14488 
14489  void mutate(Model<TSeq> * model);
14490  void set_mutation(MutFun<TSeq> fun);
14491 
14492  EPI_TYPENAME_TRAITS(TSeq, int) get_sequence();
14493  void set_sequence(TSeq sequence);
14494 
14495  Agent<TSeq> * get_agent();
14496  void set_agent(Agent<TSeq> * p);
14497 
14498  void set_date(int d);
14499  int get_date() const;
14500 
14501  void set_id(int idx);
14502  int get_id() const;
14503 
14513  epiworld_double get_prob_infecting(Model<TSeq> * model);
14514  epiworld_double get_prob_recovery(Model<TSeq> * model);
14515  epiworld_double get_prob_death(Model<TSeq> * model);
14516  epiworld_double get_incubation(Model<TSeq> * model);
14517 
14518  void post_recovery(Model<TSeq> * model);
14519  void set_post_recovery(PostRecoveryFun<TSeq> fun);
14520  void set_post_immunity(epiworld_double prob);
14521  void set_post_immunity(epiworld_double * prob);
14522 
14523  void set_prob_infecting_fun(VirusFun<TSeq> fun);
14524  void set_prob_recovery_fun(VirusFun<TSeq> fun);
14525  void set_prob_death_fun(VirusFun<TSeq> fun);
14526  void set_incubation_fun(VirusFun<TSeq> fun);
14527 
14528  void set_prob_infecting(const epiworld_double * prob);
14529  void set_prob_recovery(const epiworld_double * prob);
14530  void set_prob_death(const epiworld_double * prob);
14531  void set_incubation(const epiworld_double * prob);
14532 
14533  void set_prob_infecting(epiworld_double prob);
14534  void set_prob_recovery(epiworld_double prob);
14535  void set_prob_death(epiworld_double prob);
14536  void set_incubation(epiworld_double prob);
14538 
14539 
14540  void set_name(std::string name);
14541  std::string get_name() const;
14542 
14556  void set_state(
14557  epiworld_fast_int init,
14558  epiworld_fast_int end,
14559  epiworld_fast_int removed = -99
14560  );
14561 
14562  void set_queue(
14563  epiworld_fast_int init,
14564  epiworld_fast_int end,
14565  epiworld_fast_int removed = -99
14566  );
14567 
14568  void get_state(
14569  epiworld_fast_int * init,
14570  epiworld_fast_int * end,
14571  epiworld_fast_int * removed = nullptr
14572  );
14573 
14574  void get_queue(
14575  epiworld_fast_int * init,
14576  epiworld_fast_int * end,
14577  epiworld_fast_int * removed = nullptr
14578  );
14580 
14581  bool operator==(const Virus<TSeq> & other) const;
14582  bool operator!=(const Virus<TSeq> & other) const {return !operator==(other);};
14583 
14584  void print() const;
14585 
14590  void distribute(Model<TSeq> * model);
14591  void set_distribution(VirusToAgentFun<TSeq> fun);
14593 
14594 
14595 };
14596 
14597 #endif
14598 /*//////////////////////////////////////////////////////////////////////////////
14600 
14601  End of -include/epiworld/virus-bones.hpp-
14602 
14605 
14606 
14607 /*//////////////////////////////////////////////////////////////////////////////
14609 
14610  Start of -include/epiworld/virus-distribute-meat.hpp-
14611 
14614 
14615 
14616 #ifndef EPIWORLD_VIRUS_DISTRIBUTE_MEAT_HPP
14617 #define EPIWORLD_VIRUS_DISTRIBUTE_MEAT_HPP
14618 
14631 template<typename TSeq = EPI_DEFAULT_TSEQ>
14632 inline VirusToAgentFun<TSeq> distribute_virus_to_set(
14633  std::vector< size_t > agents_ids
14634 ) {
14635 
14636  return [agents_ids](
14637  Virus<TSeq> & virus, Model<TSeq> * model
14638  ) -> void
14639  {
14640  // Adding action
14641  for (auto i: agents_ids)
14642  {
14643  model->get_agent(i).set_virus(
14644  virus,
14645  const_cast<Model<TSeq> * >(model)
14646  );
14647  }
14648  };
14649 
14650 }
14651 
14662 template<typename TSeq = EPI_DEFAULT_TSEQ>
14663 inline VirusToAgentFun<TSeq> distribute_virus_randomly(
14664  epiworld_double prevalence,
14665  bool prevalence_as_proportion = true,
14666  std::vector< size_t > agents_ids = {}
14667 ) {
14668 
14669  auto agents_ids_ptr = std::make_shared< std::vector< size_t > >(agents_ids);
14670 
14671  return [prevalence,prevalence_as_proportion,agents_ids_ptr](
14672  Virus<TSeq> & virus, Model<TSeq> * model
14673  ) -> void
14674  {
14675 
14676  // Figuring out how what agents are available
14677  bool use_set = agents_ids_ptr->size() > 0;
14678  std::vector< size_t > idx;
14679  if (use_set)
14680  {
14681  for (const auto & agent: *agents_ids_ptr)
14682  if (model->get_agent(agent).get_virus() == nullptr)
14683  idx.push_back(agent);
14684  }
14685  else
14686  {
14687  for (const auto & agent: model->get_agents())
14688  if (agent.get_virus() == nullptr)
14689  idx.push_back(agent.get_id());
14690  }
14691 
14692  // Picking how many
14693  int n = use_set ?
14694  static_cast<int>(idx.size()) :
14695  static_cast<int>(model->size())
14696  ;
14697 
14698  int n_available = static_cast<int>(idx.size());
14699  int n_to_sample;
14700  if (prevalence_as_proportion)
14701  {
14702  n_to_sample = static_cast<int>(std::floor(
14703  prevalence * static_cast< epiworld_double >(n)
14704  ));
14705 
14706  // Correcting for possible overflow
14707  if (n_to_sample > n)
14708  n_to_sample = n;
14709  }
14710  else
14711  {
14712  n_to_sample = static_cast<int>(prevalence);
14713  }
14714 
14715  if (n_to_sample > n_available)
14716  throw std::range_error(
14717  "There are only " + std::to_string(n_available) +
14718  " individuals with no virus in the population. " +
14719  "Cannot add the virus to " +
14720  std::to_string(n_to_sample)
14721  );
14722 
14723  auto & population = model->get_agents();
14724  for (int i = 0; i < n_to_sample; ++i)
14725  {
14726 
14727  int loc = static_cast<epiworld_fast_uint>(
14728  floor(model->runif() * (n_available--))
14729  );
14730 
14731  // Correcting for possible overflow
14732  if ((loc > 0) && (loc >= n_available))
14733  loc = n_available - 1;
14734 
14735  Agent<TSeq> & agent = population[idx[loc]];
14736 
14737  // Adding action
14738  agent.set_virus(
14739  virus,
14740  const_cast<Model<TSeq> * >(model)
14741  );
14742 
14743  // Adjusting sample
14744  std::swap(idx[loc], idx[n_available]);
14745 
14746  }
14747 
14748  };
14749 
14750 }
14751 
14752 #endif
14753 /*//////////////////////////////////////////////////////////////////////////////
14755 
14756  End of -include/epiworld/virus-distribute-meat.hpp-
14757 
14760 
14761 
14762 /*//////////////////////////////////////////////////////////////////////////////
14764 
14765  Start of -include/epiworld/virus-meat.hpp-
14766 
14769 
14770 
14771 #ifndef EPIWORLD_VIRUS_MEAT_HPP
14772 #define EPIWORLD_VIRUS_MEAT_HPP
14773 
14774 /*//////////////////////////////////////////////////////////////////////////////
14776 
14777  Start of -include/epiworld/config.hpp-
14778 
14781 
14782 
14783 #ifndef EPIWORLD_CONFIG_HPP
14784 #define EPIWORLD_CONFIG_HPP
14785 
14786 #ifndef printf_epiworld
14787  #define printf_epiworld fflush(stdout);printf
14788 #endif
14789 
14790 // In case the user has a way to stop the program
14791 // This is called during `run_multiple()` and it is
14792 // passed the simulation number.
14793 #ifndef EPI_CHECK_USER_INTERRUPT
14794  #define EPI_CHECK_USER_INTERRUPT(a)
14795 #endif
14796 
14797 #ifndef EPIWORLD_MAXNEIGHBORS
14798  #define EPIWORLD_MAXNEIGHBORS 1048576
14799 #endif
14800 
14801 #if defined(_OPENMP) || defined(__OPENMP)
14802  #include <omp.h>
14803 // #else
14804 // #define omp_get_thread_num() 0
14805 // #define omp_set_num_threads() 1
14806 #endif
14807 
14808 #ifndef epiworld_double
14809  #define epiworld_double float
14810 #endif
14811 
14812 #ifndef epiworld_fast_int
14813  #define epiworld_fast_int int
14814 #endif
14815 
14816 #ifndef epiworld_fast_uint
14817  #define epiworld_fast_uint unsigned long long int
14818 #endif
14819 
14820 #define EPI_DEFAULT_TSEQ int
14821 
14822 #ifndef EPI_MAX_TRACKING
14823  #define EPI_MAX_TRACKING 200
14824 #endif
14825 
14826 template<typename TSeq = EPI_DEFAULT_TSEQ>
14827 class Model;
14828 
14829 template<typename TSeq = EPI_DEFAULT_TSEQ>
14830 class Agent;
14831 
14832 template<typename TSeq = EPI_DEFAULT_TSEQ>
14833 class PersonTools;
14834 
14835 template<typename TSeq = EPI_DEFAULT_TSEQ>
14836 class Virus;
14837 
14838 template<typename TSeq = EPI_DEFAULT_TSEQ>
14839 class Viruses;
14840 
14841 template<typename TSeq = EPI_DEFAULT_TSEQ>
14842 class Viruses_const;
14843 
14844 template<typename TSeq = EPI_DEFAULT_TSEQ>
14845 class Tool;
14846 
14847 template<typename TSeq = EPI_DEFAULT_TSEQ>
14848 class Tools;
14849 
14850 template<typename TSeq = EPI_DEFAULT_TSEQ>
14851 class Tools_const;
14852 
14853 template<typename TSeq = EPI_DEFAULT_TSEQ>
14854 class Entity;
14855 
14856 template<typename TSeq = EPI_DEFAULT_TSEQ>
14857 using VirusPtr = std::shared_ptr< Virus< TSeq > >;
14858 
14859 template<typename TSeq = EPI_DEFAULT_TSEQ>
14860 using ToolPtr = std::shared_ptr< Tool< TSeq > >;
14861 
14862 template<typename TSeq = EPI_DEFAULT_TSEQ>
14863 using ToolFun = std::function<epiworld_double(Tool<TSeq>&,Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
14864 
14865 template<typename TSeq = EPI_DEFAULT_TSEQ>
14866 using MixerFun = std::function<epiworld_double(Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
14867 
14868 template<typename TSeq = EPI_DEFAULT_TSEQ>
14869 using MutFun = std::function<bool(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
14870 
14871 template<typename TSeq = EPI_DEFAULT_TSEQ>
14872 using PostRecoveryFun = std::function<void(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
14873 
14874 template<typename TSeq = EPI_DEFAULT_TSEQ>
14875 using VirusFun = std::function<epiworld_double(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
14876 
14877 template<typename TSeq = EPI_DEFAULT_TSEQ>
14878 using UpdateFun = std::function<void(Agent<TSeq>*,Model<TSeq>*)>;
14879 
14880 template<typename TSeq = EPI_DEFAULT_TSEQ>
14881 using GlobalFun = std::function<void(Model<TSeq>*)>;
14882 
14883 template<typename TSeq>
14884 struct Event;
14885 
14886 template<typename TSeq = EPI_DEFAULT_TSEQ>
14887 using EventFun = std::function<void(Event<TSeq>&,Model<TSeq>*)>;
14888 
14892 template<typename TSeq = EPI_DEFAULT_TSEQ>
14893 using VirusToAgentFun = std::function<void(Virus<TSeq>&,Model<TSeq>*)>;
14894 
14898 template<typename TSeq = EPI_DEFAULT_TSEQ>
14899 using ToolToAgentFun = std::function<void(Tool<TSeq>&,Model<TSeq>*)>;
14900 
14904 template<typename TSeq = EPI_DEFAULT_TSEQ>
14905 using EntityToAgentFun = std::function<void(Entity<TSeq>&,Model<TSeq>*)>;
14906 
14912 template<typename TSeq = EPI_DEFAULT_TSEQ>
14913 struct Event {
14914  Agent<TSeq> * agent;
14915  VirusPtr<TSeq> virus;
14916  ToolPtr<TSeq> tool;
14917  Entity<TSeq> * entity;
14918  epiworld_fast_int new_state;
14919  epiworld_fast_int queue;
14920  EventFun<TSeq> call;
14921  int idx_agent;
14922  int idx_object;
14923 public:
14940  Event(
14941  Agent<TSeq> * agent_,
14942  VirusPtr<TSeq> & virus_,
14943  ToolPtr<TSeq> & tool_,
14944  Entity<TSeq> * entity_,
14945  epiworld_fast_int new_state_,
14946  epiworld_fast_int queue_,
14947  EventFun<TSeq> & call_,
14948  int idx_agent_,
14949  int idx_object_
14950  ) : agent(agent_), virus(virus_), tool(tool_), entity(entity_),
14951  new_state(new_state_),
14952  queue(queue_), call(call_), idx_agent(idx_agent_), idx_object(idx_object_) {
14953  return;
14954  };
14955 };
14956 
14964 #ifndef DEFAULT_TOOL_CONTAGION_REDUCTION
14965  #define DEFAULT_TOOL_CONTAGION_REDUCTION 0.0
14966 #endif
14967 
14968 #ifndef DEFAULT_TOOL_TRANSMISSION_REDUCTION
14969  #define DEFAULT_TOOL_TRANSMISSION_REDUCTION 0.0
14970 #endif
14971 
14972 #ifndef DEFAULT_TOOL_RECOVERY_ENHANCER
14973  #define DEFAULT_TOOL_RECOVERY_ENHANCER 0.0
14974 #endif
14975 
14976 #ifndef DEFAULT_TOOL_DEATH_REDUCTION
14977  #define DEFAULT_TOOL_DEATH_REDUCTION 0.0
14978 #endif
14979 
14980 #ifndef EPI_DEFAULT_VIRUS_PROB_INFECTION
14981  #define EPI_DEFAULT_VIRUS_PROB_INFECTION 1.0
14982 #endif
14983 
14984 #ifndef EPI_DEFAULT_VIRUS_PROB_RECOVERY
14985  #define EPI_DEFAULT_VIRUS_PROB_RECOVERY 0.1428
14986 #endif
14987 
14988 #ifndef EPI_DEFAULT_VIRUS_PROB_DEATH
14989  #define EPI_DEFAULT_VIRUS_PROB_DEATH 0.0
14990 #endif
14991 
14992 #ifndef EPI_DEFAULT_INCUBATION_DAYS
14993  #define EPI_DEFAULT_INCUBATION_DAYS 7.0
14994 #endif
14996 
14997 #ifdef EPI_DEBUG
14998  #define EPI_DEBUG_PRINTF printf_epiworld
14999 
15000  #define EPI_DEBUG_ERROR(etype, msg) \
15001  (etype)("[[epi-debug]] (error) " + std::string(msg));
15002 
15003  #define EPI_DEBUG_NOTIFY_ACTIVE() \
15004  EPI_DEBUG_PRINTF("DEBUGGING ON (compiled with EPI_DEBUG defined)%s\n", "");
15005 
15006  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect) \
15007  for (auto & v : vect) \
15008  if (static_cast<double>(v) < 0.0) \
15009  throw EPI_DEBUG_ERROR(std::logic_error, "A negative value not allowed.");
15010 
15011  #define EPI_DEBUG_SUM_DBL(vect, num) \
15012  double _epi_debug_sum = 0.0; \
15013  for (auto & v : vect) \
15014  { \
15015  _epi_debug_sum += static_cast<double>(v);\
15016  if (_epi_debug_sum > static_cast<double>(num)) \
15017  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
15018  }
15019 
15020  #define EPI_DEBUG_SUM_INT(vect, num) \
15021  int _epi_debug_sum = 0; \
15022  for (auto & v : vect) \
15023  { \
15024  _epi_debug_sum += static_cast<int>(v);\
15025  if (_epi_debug_sum > static_cast<int>(num)) \
15026  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
15027  }
15028 
15029  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c) \
15030  if (a.size() != b.size()) {\
15031  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
15032  EPI_DEBUG_PRINTF("Size of vector a: %lu\n", (a).size());\
15033  EPI_DEBUG_PRINTF("Size of vector b: %lu\n", (b).size());\
15034  throw EPI_DEBUG_ERROR(std::length_error, "The vectors do not match size."); \
15035  }\
15036  for (int _i = 0; _i < static_cast<int>(a.size()); ++_i) \
15037  if (a[_i] != b[_i]) {\
15038  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
15039  EPI_DEBUG_PRINTF("Iterating the last 5 values%s:\n", ""); \
15040  for (int _j = std::max(0, static_cast<int>(_i) - 4); _j <= _i; ++_j) \
15041  { \
15042  EPI_DEBUG_PRINTF( \
15043  "a[%i]: %i; b[%i]: %i\n", \
15044  _j, \
15045  static_cast<int>(a[_j]), \
15046  _j, static_cast<int>(b[_j])); \
15047  } \
15048  throw EPI_DEBUG_ERROR(std::logic_error, "The vectors do not match."); \
15049  }
15050 
15051  #define EPI_DEBUG_FAIL_AT_TRUE(a,b) \
15052  if (a) \
15053  {\
15054  throw EPI_DEBUG_ERROR(std::logic_error, b); \
15055  }
15056 
15057  #define epiexception(a) std::logic_error
15058 #else
15059  #define EPI_DEBUG_PRINTF(fmt, ...)
15060  #define EPI_DEBUG_ERROR(fmt, ...)
15061  #define EPI_DEBUG_NOTIFY_ACTIVE()
15062  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect)
15063  #define EPI_DEBUG_SUM_DBL(vect, num)
15064  #define EPI_DEBUG_SUM_INT(vect, num)
15065  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c)
15066  #define EPI_DEBUG_FAIL_AT_TRUE(a, b) \
15067  if (a) \
15068  return false;
15069  #define epiexception(a) a
15070 #endif
15071 
15072 #if defined(EPI_DEBUG_NO_THREAD_ID) || (!defined(__OPENMP) && !defined(_OPENMP))
15073  #define EPI_GET_THREAD_ID() 0
15074 #else
15075  #define EPI_GET_THREAD_ID() omp_get_thread_num()
15076 #endif
15077 
15078 #endif
15079 /*//////////////////////////////////////////////////////////////////////////////
15081 
15082  End of -include/epiworld/config.hpp-
15083 
15086 
15087 
15088 
15097 template<typename TSeq>
15098 inline VirusFun<TSeq> virus_fun_logit(
15099  std::vector< int > vars,
15100  std::vector< double > coefs,
15101  Model<TSeq> * model,
15102  bool logit = true
15103 ) {
15104 
15105  // Checking that there are features
15106  if (coefs.size() == 0u)
15107  throw std::logic_error(
15108  "The -coefs- argument should feature at least one element."
15109  );
15110 
15111  if (coefs.size() != vars.size())
15112  throw std::length_error(
15113  std::string("The length of -coef- (") +
15114  std::to_string(coefs.size()) +
15115  std::string(") and -vars- (") +
15116  std::to_string(vars.size()) +
15117  std::string(") should match. ")
15118  );
15119 
15120  // Checking that there are variables in the model
15121  if (model != nullptr)
15122  {
15123 
15124  size_t K = model->get_agents_data_ncols();
15125  for (const auto & var: vars)
15126  {
15127  if ((var >= static_cast<int>(K)) | (var < 0))
15128  throw std::range_error(
15129  std::string("The variable ") +
15130  std::to_string(var) +
15131  std::string(" is out of range.") +
15132  std::string(" The agents only feature ") +
15133  std::to_string(K) +
15134  std::string("variables (features).")
15135  );
15136  }
15137 
15138  }
15139 
15140  std::vector< epiworld_double > coefs_f;
15141  for (auto c: coefs)
15142  coefs_f.push_back(static_cast<epiworld_double>(c));
15143 
15144  VirusFun<TSeq> fun_infect = [coefs_f,vars](
15145  Agent<TSeq> * agent,
15146  Virus<TSeq> &,
15147  Model<TSeq> *
15148  ) -> epiworld_double {
15149 
15150  size_t K = coefs_f.size();
15151  epiworld_double res = 0.0;
15152 
15153  #if defined(__OPENMP) || defined(_OPENMP)
15154  #pragma omp simd reduction(+:res)
15155  #endif
15156  for (size_t i = 0u; i < K; ++i)
15157  res += agent->operator[](vars.at(i)) * coefs_f.at(i);
15158 
15159  return 1.0/(1.0 + std::exp(-res));
15160 
15161  };
15162 
15163  return fun_infect;
15164 
15165 }
15166 
15167 template<typename TSeq>
15168 inline Virus<TSeq>::Virus()
15169 {
15170 
15171  #ifdef EPI_DEBUG_VIRUS
15172  counter_construct++;
15173  #endif
15174 
15175  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
15176  {
15177  baseline_sequence = -1;
15178  }
15179  else
15180  {
15181  baseline_sequence = nullptr;
15182  }
15183 
15184 }
15185 
15186 template<typename TSeq>
15187 inline Virus<TSeq>::Virus(
15188  std::string name
15189  ) {
15190 
15191  #ifdef EPI_DEBUG_VIRUS
15192  counter_construct++;
15193  #endif
15194 
15195  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
15196  {
15197  baseline_sequence = -1;
15198  }
15199  else
15200  {
15201  baseline_sequence = nullptr;
15202  }
15203 
15204  set_name(name);
15205 }
15206 
15207 template<typename TSeq>
15208 inline Virus<TSeq>::Virus(
15209  std::string name,
15210  epiworld_double prevalence,
15211  bool prevalence_as_proportion
15212  ) {
15213 
15214  #ifdef EPI_DEBUG_VIRUS
15215  counter_construct++;
15216  #endif
15217 
15218  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
15219  {
15220  baseline_sequence = -1;
15221  }
15222  else
15223  {
15224  baseline_sequence = nullptr;
15225  }
15226 
15227  set_name(name);
15228  set_distribution(
15229  distribute_virus_randomly<TSeq>(
15230  prevalence,
15231  prevalence_as_proportion
15232  )
15233  );
15234 }
15235 
15236 #ifdef EPI_DEBUG_VIRUS
15237 template<typename TSeq>
15238 std::atomic<int> Virus<TSeq>::counter_construct = 0;
15239 
15240 template<typename TSeq>
15241 std::atomic<int> Virus<TSeq>::counter_copy_construct = 0;
15242 
15243 template<typename TSeq>
15244 std::atomic<int> Virus<TSeq>::counter_move_construct = 0;
15245 
15246 template<typename TSeq>
15247 std::atomic<int> Virus<TSeq>::counter_copy_assign = 0;
15248 
15249 template<typename TSeq>
15250 std::atomic<int> Virus<TSeq>::counter_move_assign = 0;
15251 
15252 template<typename TSeq>
15253 std::atomic<int> Virus<TSeq>::counter_destruct = 0;
15254 
15255 template<typename TSeq>
15256 inline Virus<TSeq>::~Virus()
15257 {
15258  counter_destruct++;
15259 }
15260 
15261 // Copy constructor
15262 template<typename TSeq>
15263 inline Virus<TSeq>::Virus(const Virus<TSeq>& other)
15264  : agent(other.agent),
15265  baseline_sequence(other.baseline_sequence),
15266  virus_name(other.virus_name),
15267  date(other.date),
15268  id(other.id),
15269  state_init(other.state_init),
15270  state_post(other.state_post),
15271  state_removed(other.state_removed),
15272  queue_init(other.queue_init),
15273  queue_post(other.queue_post),
15274  queue_removed(other.queue_removed),
15275  virus_functions(other.virus_functions)
15276 {
15277  counter_copy_construct++;
15278 }
15279 
15280 // Move constructor
15281 template<typename TSeq>
15282 inline Virus<TSeq>::Virus(Virus<TSeq>&& other) noexcept
15283  : agent(other.agent),
15284  baseline_sequence(std::move(other.baseline_sequence)),
15285  virus_name(std::move(other.virus_name)),
15286  date(other.date),
15287  id(other.id),
15288  state_init(other.state_init),
15289  state_post(other.state_post),
15290  state_removed(other.state_removed),
15291  queue_init(other.queue_init),
15292  queue_post(other.queue_post),
15293  queue_removed(other.queue_removed),
15294  virus_functions(std::move(other.virus_functions))
15295 {
15296  counter_move_construct++;
15297  // other.agent = nullptr;
15298 }
15299 
15300 // Copy assignment
15301 template<typename TSeq>
15302 inline Virus<TSeq>& Virus<TSeq>::operator=(const Virus<TSeq>& other)
15303 {
15304  if (this != &other) {
15305  agent = other.agent;
15306  baseline_sequence = other.baseline_sequence;
15307  virus_name = other.virus_name;
15308  date = other.date;
15309  id = other.id;
15310  state_init = other.state_init;
15311  state_post = other.state_post;
15312  state_removed = other.state_removed;
15313  queue_init = other.queue_init;
15314  queue_post = other.queue_post;
15315  queue_removed = other.queue_removed;
15316  virus_functions = other.virus_functions;
15317  counter_copy_assign++;
15318  }
15319  return *this;
15320 }
15321 
15322 // Move assignment
15323 template<typename TSeq>
15324 inline Virus<TSeq>& Virus<TSeq>::operator=(Virus<TSeq>&& other) noexcept
15325 {
15326  if (this != &other) {
15327  agent = other.agent;
15328  baseline_sequence = std::move(other.baseline_sequence);
15329  virus_name = std::move(other.virus_name);
15330  date = other.date;
15331  id = other.id;
15332  state_init = other.state_init;
15333  state_post = other.state_post;
15334  state_removed = other.state_removed;
15335  queue_init = other.queue_init;
15336  queue_post = other.queue_post;
15337  queue_removed = other.queue_removed;
15338  virus_functions = std::move(other.virus_functions);
15339  other.agent = nullptr;
15340  counter_move_assign++;
15341  }
15342  return *this;
15343 }
15344 #endif
15345 
15346 template<typename TSeq>
15347 inline void Virus<TSeq>::mutate(
15348  Model<TSeq> * model
15349 ) {
15350 
15351  if (virus_functions->mutation)
15352  if (virus_functions->mutation(agent, *this, model))
15353  model->get_db().record_virus(*this);
15354 
15355  return;
15356 
15357 }
15358 
15359 template<typename TSeq>
15360 inline void Virus<TSeq>::set_mutation(
15361  MutFun<TSeq> fun
15362 ) {
15363  virus_functions->mutation = MutFun<TSeq>(fun);
15364 }
15365 
15366 template<typename TSeq>
15367 inline EPI_TYPENAME_TRAITS(TSeq, int) Virus<TSeq>::get_sequence()
15368 {
15369 
15370  return baseline_sequence;
15371 
15372 }
15373 
15374 template<typename TSeq>
15375 inline void Virus<TSeq>::set_sequence(TSeq sequence)
15376 {
15377 
15378  baseline_sequence = std::make_shared<TSeq>(sequence);
15379  return;
15380 
15381 }
15382 
15383 template<>
15384 inline void Virus<int>::set_sequence(int sequence)
15385 {
15386 
15387  baseline_sequence = sequence;
15388  return;
15389 
15390 }
15391 
15392 
15393 template<typename TSeq>
15394 inline Agent<TSeq> * Virus<TSeq>::get_agent()
15395 {
15396 
15397  return agent;
15398 
15399 }
15400 
15401 template<typename TSeq>
15402 inline void Virus<TSeq>::set_agent(Agent<TSeq> * p)
15403 {
15404  agent = p;
15405 }
15406 
15407 template<typename TSeq>
15408 inline void Virus<TSeq>::set_id(int idx)
15409 {
15410 
15411  id = idx;
15412  return;
15413 
15414 }
15415 
15416 template<typename TSeq>
15417 inline int Virus<TSeq>::get_id() const
15418 {
15419 
15420  return id;
15421 
15422 }
15423 
15424 template<typename TSeq>
15425 inline void Virus<TSeq>::set_date(int d)
15426 {
15427 
15428  date = d;
15429  return;
15430 
15431 }
15432 
15433 template<typename TSeq>
15434 inline int Virus<TSeq>::get_date() const
15435 {
15436 
15437  return date;
15438 
15439 }
15440 
15441 template<typename TSeq>
15442 inline epiworld_double Virus<TSeq>::get_prob_infecting(
15443  Model<TSeq> * model
15444 )
15445 {
15446 
15447  if (virus_functions->probability_of_infecting)
15448  return virus_functions->probability_of_infecting(agent, *this, model);
15449 
15450  return EPI_DEFAULT_VIRUS_PROB_INFECTION;
15451 
15452 }
15453 
15454 
15455 
15456 template<typename TSeq>
15457 inline epiworld_double Virus<TSeq>::get_prob_recovery(
15458  Model<TSeq> * model
15459 )
15460 {
15461 
15462  if (virus_functions->probability_of_recovery)
15463  return virus_functions->probability_of_recovery(agent, *this, model);
15464 
15465  return EPI_DEFAULT_VIRUS_PROB_RECOVERY;
15466 
15467 }
15468 
15469 
15470 
15471 template<typename TSeq>
15472 inline epiworld_double Virus<TSeq>::get_prob_death(
15473  Model<TSeq> * model
15474 )
15475 {
15476 
15477  if (virus_functions->probability_of_death)
15478  return virus_functions->probability_of_death(agent, *this, model);
15479 
15480  return EPI_DEFAULT_VIRUS_PROB_DEATH;
15481 
15482 }
15483 
15484 template<typename TSeq>
15485 inline epiworld_double Virus<TSeq>::get_incubation(
15486  Model<TSeq> * model
15487 )
15488 {
15489 
15490  if (virus_functions->incubation)
15491  return virus_functions->incubation(agent, *this, model);
15492 
15493  return EPI_DEFAULT_INCUBATION_DAYS;
15494 
15495 }
15496 
15497 template<typename TSeq>
15498 inline void Virus<TSeq>::set_prob_infecting_fun(VirusFun<TSeq> fun)
15499 {
15500  virus_functions->probability_of_infecting = fun;
15501 }
15502 
15503 template<typename TSeq>
15504 inline void Virus<TSeq>::set_prob_recovery_fun(VirusFun<TSeq> fun)
15505 {
15506  virus_functions->probability_of_recovery = fun;
15507 }
15508 
15509 template<typename TSeq>
15510 inline void Virus<TSeq>::set_prob_death_fun(VirusFun<TSeq> fun)
15511 {
15512  virus_functions->probability_of_death = fun;
15513 }
15514 
15515 template<typename TSeq>
15516 inline void Virus<TSeq>::set_incubation_fun(VirusFun<TSeq> fun)
15517 {
15518  virus_functions->incubation = fun;
15519 }
15520 
15521 template<typename TSeq>
15522 inline void Virus<TSeq>::set_prob_infecting(const epiworld_double * prob)
15523 {
15524  VirusFun<TSeq> tmpfun =
15525  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15526  {
15527  return *prob;
15528  };
15529 
15530  virus_functions->probability_of_infecting = tmpfun;
15531 }
15532 
15533 template<typename TSeq>
15534 inline void Virus<TSeq>::set_prob_recovery(const epiworld_double * prob)
15535 {
15536  VirusFun<TSeq> tmpfun =
15537  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15538  {
15539  return *prob;
15540  };
15541 
15542  virus_functions->probability_of_recovery = tmpfun;
15543 }
15544 
15545 template<typename TSeq>
15546 inline void Virus<TSeq>::set_prob_death(const epiworld_double * prob)
15547 {
15548  VirusFun<TSeq> tmpfun =
15549  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15550  {
15551  return *prob;
15552  };
15553 
15554  virus_functions->probability_of_death = tmpfun;
15555 }
15556 
15557 template<typename TSeq>
15558 inline void Virus<TSeq>::set_incubation(const epiworld_double * prob)
15559 {
15560  VirusFun<TSeq> tmpfun =
15561  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15562  {
15563  return *prob;
15564  };
15565 
15566  virus_functions->incubation = tmpfun;
15567 }
15568 
15569 template<typename TSeq>
15570 inline void Virus<TSeq>::set_prob_infecting(epiworld_double prob)
15571 {
15572  VirusFun<TSeq> tmpfun =
15573  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15574  {
15575  return prob;
15576  };
15577 
15578  virus_functions->probability_of_infecting = tmpfun;
15579 }
15580 
15581 template<typename TSeq>
15582 inline void Virus<TSeq>::set_prob_recovery(epiworld_double prob)
15583 {
15584  VirusFun<TSeq> tmpfun =
15585  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15586  {
15587  return prob;
15588  };
15589 
15590  virus_functions->probability_of_recovery = tmpfun;
15591 }
15592 
15593 template<typename TSeq>
15594 inline void Virus<TSeq>::set_prob_death(epiworld_double prob)
15595 {
15596  VirusFun<TSeq> tmpfun =
15597  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15598  {
15599  return prob;
15600  };
15601 
15602  virus_functions->probability_of_death = tmpfun;
15603 }
15604 
15605 template<typename TSeq>
15606 inline void Virus<TSeq>::set_incubation(epiworld_double prob)
15607 {
15608  VirusFun<TSeq> tmpfun =
15609  [prob](Agent<TSeq> *, Virus<TSeq> &, Model<TSeq> *)
15610  {
15611  return prob;
15612  };
15613 
15614  virus_functions->incubation = tmpfun;
15615 }
15616 
15617 template<typename TSeq>
15618 inline void Virus<TSeq>::set_post_recovery(PostRecoveryFun<TSeq> fun)
15619 {
15620  if (virus_functions->post_recovery)
15621  {
15622  printf_epiworld(
15623  "Warning: a PostRecoveryFun is alreay in place (overwriting)."
15624  );
15625  }
15626 
15627  virus_functions->post_recovery = fun;
15628 }
15629 
15630 template<typename TSeq>
15631 inline void Virus<TSeq>::post_recovery(
15632  Model<TSeq> * model
15633 )
15634 {
15635 
15636  if (virus_functions->post_recovery)
15637  virus_functions->post_recovery(agent, *this, model);
15638 
15639  return;
15640 
15641 }
15642 
15643 template<typename TSeq>
15644 inline void Virus<TSeq>::set_post_immunity(
15645  epiworld_double prob
15646 )
15647 {
15648 
15649  if (virus_functions->post_recovery)
15650  {
15651 
15652  std::string msg =
15653  std::string(
15654  "You cannot set post immunity when a post_recovery "
15655  ) +
15656  std::string(
15657  "function is already in place. Redesign the post_recovery function."
15658  );
15659 
15660  throw std::logic_error(msg);
15661 
15662  }
15663 
15664  // To make sure that we keep registering the virus
15665  ToolPtr<TSeq> __no_reinfect = std::make_shared<Tool<TSeq>>(
15666  "Immunity (" + virus_name + ")"
15667  );
15668 
15669  __no_reinfect->set_susceptibility_reduction(prob);
15670  __no_reinfect->set_death_reduction(0.0);
15671  __no_reinfect->set_transmission_reduction(0.0);
15672  __no_reinfect->set_recovery_enhancer(0.0);
15673 
15674  PostRecoveryFun<TSeq> tmpfun =
15675  [__no_reinfect](
15676  Agent<TSeq> * p, Virus<TSeq> &, Model<TSeq> * m
15677  )
15678  {
15679 
15680  // Have we registered the tool?
15681  if (__no_reinfect->get_id() == -99)
15682  m->get_db().record_tool(*__no_reinfect);
15683 
15684  p->add_tool(*__no_reinfect, m);
15685 
15686  return;
15687 
15688  };
15689 
15690  virus_functions->post_recovery = tmpfun;
15691 
15692 }
15693 
15694 template<typename TSeq>
15695 inline void Virus<TSeq>::set_post_immunity(
15696  epiworld_double * prob
15697 )
15698 {
15699 
15700  if (virus_functions->post_recovery)
15701  {
15702 
15703  std::string msg =
15704  std::string(
15705  "You cannot set post immunity when a post_recovery "
15706  ) +
15707  std::string(
15708  "function is already in place. Redesign the post_recovery function."
15709  );
15710 
15711  throw std::logic_error(msg);
15712 
15713  }
15714 
15715  // To make sure that we keep registering the virus
15716  ToolPtr<TSeq> __no_reinfect = std::make_shared<Tool<TSeq>>(
15717  "Immunity (" + virus_name + ")"
15718  );
15719 
15720  __no_reinfect->set_susceptibility_reduction(prob);
15721  __no_reinfect->set_death_reduction(0.0);
15722  __no_reinfect->set_transmission_reduction(0.0);
15723  __no_reinfect->set_recovery_enhancer(0.0);
15724 
15725  PostRecoveryFun<TSeq> tmpfun =
15726  [__no_reinfect](Agent<TSeq> * p, Virus<TSeq> &, Model<TSeq> * m)
15727  {
15728 
15729  // Have we registered the tool?
15730  if (__no_reinfect->get_id() == -99)
15731  m->get_db().record_tool(*__no_reinfect);
15732 
15733  p->add_tool(*__no_reinfect, m);
15734 
15735  return;
15736 
15737  };
15738 
15739  virus_functions->post_recovery = tmpfun;
15740 
15741 }
15742 
15743 template<typename TSeq>
15744 inline void Virus<TSeq>::set_name(std::string name)
15745 {
15746 
15747  virus_name = name;
15748 
15749 }
15750 
15751 template<typename TSeq>
15752 inline std::string Virus<TSeq>::get_name() const
15753 {
15754 
15755  return virus_name;
15756 
15757 }
15758 
15759 template<typename TSeq>
15760 inline void Virus<TSeq>::set_state(
15761  epiworld_fast_int init,
15762  epiworld_fast_int end,
15763  epiworld_fast_int removed
15764 )
15765 {
15766  state_init = init;
15767  state_post = end;
15768  state_removed = removed;
15769 }
15770 
15771 template<typename TSeq>
15772 inline void Virus<TSeq>::set_queue(
15773  epiworld_fast_int init,
15774  epiworld_fast_int end,
15775  epiworld_fast_int removed
15776 )
15777 {
15778 
15779  queue_init = init;
15780  queue_post = end;
15781  queue_removed = removed;
15782 
15783 }
15784 
15785 template<typename TSeq>
15786 inline void Virus<TSeq>::get_state(
15787  epiworld_fast_int * init,
15788  epiworld_fast_int * end,
15789  epiworld_fast_int * removed
15790 )
15791 {
15792 
15793  if (init != nullptr)
15794  *init = state_init;
15795 
15796  if (end != nullptr)
15797  *end = state_post;
15798 
15799  if (removed != nullptr)
15800  *removed = state_removed;
15801 
15802 }
15803 
15804 template<typename TSeq>
15805 inline void Virus<TSeq>::get_queue(
15806  epiworld_fast_int * init,
15807  epiworld_fast_int * end,
15808  epiworld_fast_int * removed
15809 )
15810 {
15811 
15812  if (init != nullptr)
15813  *init = queue_init;
15814 
15815  if (end != nullptr)
15816  *end = queue_post;
15817 
15818  if (removed != nullptr)
15819  *removed = queue_removed;
15820 
15821 }
15822 
15823 template<>
15824 inline bool Virus<std::vector<int>>::operator==(
15825  const Virus<std::vector<int>> & other
15826  ) const
15827 {
15828 
15829  EPI_DEBUG_FAIL_AT_TRUE(
15830  baseline_sequence->size() != other.baseline_sequence->size(),
15831  "Virus:: baseline_sequence don't match"
15832  )
15833 
15834  for (size_t i = 0u; i < baseline_sequence->size(); ++i)
15835  {
15836 
15837  EPI_DEBUG_FAIL_AT_TRUE(
15838  baseline_sequence->operator[](i) != other.baseline_sequence->operator[](i),
15839  "Virus:: baseline_sequence[i] don't match"
15840  )
15841 
15842  }
15843 
15844  EPI_DEBUG_FAIL_AT_TRUE(
15845  virus_name != other.virus_name,
15846  "Virus:: virus_name don't match"
15847  )
15848 
15849  EPI_DEBUG_FAIL_AT_TRUE(
15850  state_init != other.state_init,
15851  "Virus:: state_init don't match"
15852  )
15853 
15854  EPI_DEBUG_FAIL_AT_TRUE(
15855  state_post != other.state_post,
15856  "Virus:: state_post don't match"
15857  )
15858 
15859  EPI_DEBUG_FAIL_AT_TRUE(
15860  state_removed != other.state_removed,
15861  "Virus:: state_removed don't match"
15862  )
15863 
15864  EPI_DEBUG_FAIL_AT_TRUE(
15865  queue_init != other.queue_init,
15866  "Virus:: queue_init don't match"
15867  )
15868 
15869  EPI_DEBUG_FAIL_AT_TRUE(
15870  queue_post != other.queue_post,
15871  "Virus:: queue_post don't match"
15872  )
15873 
15874  EPI_DEBUG_FAIL_AT_TRUE(
15875  queue_removed != other.queue_removed,
15876  "Virus:: queue_removed don't match"
15877  )
15878 
15879  return true;
15880 
15881 }
15882 
15883 template<typename TSeq>
15884 inline bool Virus<TSeq>::operator==(const Virus<TSeq> & other) const
15885 {
15886 
15887  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
15888  {
15889  EPI_DEBUG_FAIL_AT_TRUE(
15890  baseline_sequence != other.baseline_sequence,
15891  "Virus:: baseline_sequence don't match"
15892  )
15893  }
15894  else
15895  {
15896  EPI_DEBUG_FAIL_AT_TRUE(
15897  baseline_sequence != other.baseline_sequence,
15898  "Virus:: baseline_sequence don't match"
15899  )
15900  }
15901 
15902  EPI_DEBUG_FAIL_AT_TRUE(
15903  virus_name != other.virus_name,
15904  "Virus:: virus_name don't match"
15905  )
15906 
15907  EPI_DEBUG_FAIL_AT_TRUE(
15908  state_init != other.state_init,
15909  "Virus:: state_init don't match"
15910  )
15911 
15912  EPI_DEBUG_FAIL_AT_TRUE(
15913  state_post != other.state_post,
15914  "Virus:: state_post don't match"
15915  )
15916 
15917  EPI_DEBUG_FAIL_AT_TRUE(
15918  state_removed != other.state_removed,
15919  "Virus:: state_removed don't match"
15920  )
15921 
15922  EPI_DEBUG_FAIL_AT_TRUE(
15923  queue_init != other.queue_init,
15924  "Virus:: queue_init don't match"
15925  )
15926 
15927  EPI_DEBUG_FAIL_AT_TRUE(
15928  queue_post != other.queue_post,
15929  "Virus:: queue_post don't match"
15930  )
15931 
15932  EPI_DEBUG_FAIL_AT_TRUE(
15933  queue_removed != other.queue_removed,
15934  "Virus:: queue_removed don't match"
15935  )
15936 
15937  return true;
15938 
15939 }
15940 
15941 template<typename TSeq>
15942 inline void Virus<TSeq>::print() const
15943 {
15944 
15945  printf_epiworld("Virus : %s\n", virus_name.c_str());
15946  printf_epiworld("Id : %s\n", (id < 0)? std::string("(empty)").c_str() : std::to_string(id).c_str());
15947  printf_epiworld("state_init : %i\n", static_cast<int>(state_init));
15948  printf_epiworld("state_post : %i\n", static_cast<int>(state_post));
15949  printf_epiworld("state_removed : %i\n", static_cast<int>(state_removed));
15950  printf_epiworld("queue_init : %i\n", static_cast<int>(queue_init));
15951  printf_epiworld("queue_post : %i\n", static_cast<int>(queue_post));
15952  printf_epiworld("queue_removed : %i\n", static_cast<int>(queue_removed));
15953 
15954 }
15955 
15956 template<typename TSeq>
15957 inline void Virus<TSeq>::distribute(Model<TSeq> * model)
15958 {
15959 
15960  if (virus_functions->dist)
15961  {
15962 
15963  virus_functions->dist(*this, model);
15964 
15965  }
15966 
15967 }
15968 
15969 template<typename TSeq>
15970 inline void Virus<TSeq>::set_distribution(VirusToAgentFun<TSeq> fun)
15971 {
15972  virus_functions->dist = fun;
15973 }
15974 
15975 #endif
15976 /*//////////////////////////////////////////////////////////////////////////////
15978 
15979  End of -include/epiworld/virus-meat.hpp-
15980 
15983 
15984 
15985 
15986 /*//////////////////////////////////////////////////////////////////////////////
15988 
15989  Start of -include/epiworld/tools-bones.hpp-
15990 
15993 
15994 
15995 #ifndef EPIWORLD_TOOLS_BONES_HPP
15996 #define EPIWORLD_TOOLS_BONES_HPP
15997 
15998 template<typename TSeq>
15999 class Tool;
16000 
16001 template<typename TSeq>
16002 class Agent;
16003 
16004 // #define ToolPtr<TSeq> std::shared_ptr< Tool<TSeq> >
16005 
16011 template<typename TSeq>
16012 class Tools {
16013  friend class Tool<TSeq>;
16014  friend class Agent<TSeq>;
16015 private:
16016  std::vector< ToolPtr<TSeq> > * dat;
16017  const unsigned int * n_tools;
16018 
16019 public:
16020 
16021  Tools() = delete;
16022  Tools(Agent<TSeq> & p) : dat(&p.tools), n_tools(&p.n_tools) {};
16023 
16024  typename std::vector< ToolPtr<TSeq> >::iterator begin();
16025  typename std::vector< ToolPtr<TSeq> >::iterator end();
16026 
16027  ToolPtr<TSeq> & operator()(size_t i);
16028  ToolPtr<TSeq> & operator[](size_t i);
16029 
16030  size_t size() const noexcept;
16031 
16032  void print() const noexcept;
16033 
16034 };
16035 
16036 template<typename TSeq>
16037 inline typename std::vector< ToolPtr<TSeq> >::iterator Tools<TSeq>::begin()
16038 {
16039 
16040  if (*n_tools == 0u)
16041  return dat->end();
16042 
16043  return dat->begin();
16044 }
16045 
16046 template<typename TSeq>
16047 inline typename std::vector< ToolPtr<TSeq> >::iterator Tools<TSeq>::end()
16048 {
16049 
16050  return begin() + *n_tools;
16051 }
16052 
16053 template<typename TSeq>
16054 inline ToolPtr<TSeq> & Tools<TSeq>::operator()(size_t i)
16055 {
16056 
16057  if (i >= *n_tools)
16058  throw std::range_error("Tool index out of range.");
16059 
16060  return dat->operator[](i);
16061 
16062 }
16063 
16064 template<typename TSeq>
16065 inline ToolPtr<TSeq> & Tools<TSeq>::operator[](size_t i)
16066 {
16067 
16068  return dat->operator[](i);
16069 
16070 }
16071 
16072 template<typename TSeq>
16073 inline size_t Tools<TSeq>::size() const noexcept
16074 {
16075  return *n_tools;
16076 }
16077 
16078 template<typename TSeq>
16079 inline void Tools<TSeq>::print() const noexcept
16080 {
16081  if (*n_tools == 0u)
16082  {
16083  printf_epiworld("List of tools (none)\n");
16084  return;
16085  }
16086 
16087  printf_epiworld("List of tools (%i): ", static_cast<int>(*n_tools));
16088 
16089  // Printing the name of each virus separated by a comma
16090  for (size_t i = 0u; i < *n_tools; ++i)
16091  {
16092  if (i == *n_tools - 1u)
16093  {
16094  printf_epiworld("%s", dat->operator[](i)->get_name().c_str());
16095  } else
16096  {
16097  printf_epiworld("%s, ", dat->operator[](i)->get_name().c_str());
16098  }
16099  }
16100 
16101  printf_epiworld("\n");
16102 
16103 }
16104 
16110 template<typename TSeq>
16111 class Tools_const {
16112  friend class Tool<TSeq>;
16113  friend class Agent<TSeq>;
16114 private:
16115  const std::vector< ToolPtr<TSeq> > * dat;
16116  const epiworld_fast_uint * n_tools;
16117 
16118 public:
16119 
16120  Tools_const() = delete;
16121  Tools_const(const Agent<TSeq> & p) : dat(&p.tools), n_tools(&p.n_tools) {};
16122 
16123  typename std::vector< ToolPtr<TSeq> >::const_iterator begin() const;
16124  typename std::vector< ToolPtr<TSeq> >::const_iterator end() const;
16125 
16126  const ToolPtr<TSeq> & operator()(size_t i);
16127  const ToolPtr<TSeq> & operator[](size_t i);
16128 
16129  size_t size() const noexcept;
16130 
16131  void print() const noexcept;
16132 
16133 };
16134 
16135 template<typename TSeq>
16136 inline typename std::vector< ToolPtr<TSeq> >::const_iterator Tools_const<TSeq>::begin() const {
16137 
16138  if (*n_tools == 0u)
16139  return dat->end();
16140 
16141  return dat->begin();
16142 }
16143 
16144 template<typename TSeq>
16145 inline typename std::vector< ToolPtr<TSeq> >::const_iterator Tools_const<TSeq>::end() const {
16146 
16147  return begin() + *n_tools;
16148 }
16149 
16150 template<typename TSeq>
16151 inline const ToolPtr<TSeq> & Tools_const<TSeq>::operator()(size_t i)
16152 {
16153 
16154  if (i >= *n_tools)
16155  throw std::range_error("Tool index out of range.");
16156 
16157  return dat->operator[](i);
16158 
16159 }
16160 
16161 template<typename TSeq>
16162 inline const ToolPtr<TSeq> & Tools_const<TSeq>::operator[](size_t i)
16163 {
16164 
16165  return dat->operator[](i);
16166 
16167 }
16168 
16169 template<typename TSeq>
16170 inline size_t Tools_const<TSeq>::size() const noexcept
16171 {
16172  return *n_tools;
16173 }
16174 
16175 template<typename TSeq>
16176 inline void Tools_const<TSeq>::print() const noexcept
16177 {
16178  if (*n_tools == 0u)
16179  {
16180  printf_epiworld("List of tools (none)\n");
16181  return;
16182  }
16183 
16184  printf_epiworld("List of tools (%i): ", *n_tools);
16185 
16186  // Printing the name of each virus separated by a comma
16187  for (size_t i = 0u; i < *n_tools; ++i)
16188  {
16189  if (i == *n_tools - 1u)
16190  {
16191  printf_epiworld("%s", dat->operator[](i)->get_name().c_str());
16192  } else
16193  {
16194  printf_epiworld("%s, ", dat->operator[](i)->get_name().c_str());
16195  }
16196  }
16197 
16198  printf_epiworld("\n");
16199 
16200 }
16201 
16202 
16203 
16204 #endif
16205 /*//////////////////////////////////////////////////////////////////////////////
16207 
16208  End of -include/epiworld/tools-bones.hpp-
16209 
16212 
16213 
16214 
16215 /*//////////////////////////////////////////////////////////////////////////////
16217 
16218  Start of -include/epiworld/tool-bones.hpp-
16219 
16222 
16223 
16224 
16225 #ifndef EPIWORLD_TOOL_BONES_HPP
16226 #define EPIWORLD_TOOL_BONES_HPP
16227 
16228 template<typename TSeq>
16229 class Virus;
16230 
16231 template<typename TSeq>
16232 class Agent;
16233 
16234 template<typename TSeq>
16235 class Model;
16236 
16237 template<typename TSeq>
16238 class Tool;
16239 
16244 template<typename TSeq>
16245 class ToolFunctions {
16246 public:
16247  ToolFun<TSeq> susceptibility_reduction = nullptr;
16248  ToolFun<TSeq> transmission_reduction = nullptr;
16249  ToolFun<TSeq> recovery_enhancer = nullptr;
16250  ToolFun<TSeq> death_reduction = nullptr;
16251 
16252  ToolToAgentFun<TSeq> dist = nullptr;
16253 
16254  ToolFunctions() = default;
16255 };
16256 
16262 template<typename TSeq>
16263 class Tool {
16264  friend class Agent<TSeq>;
16265  friend class Model<TSeq>;
16266  friend void default_add_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
16267  friend void default_rm_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
16268 private:
16269 
16270  Agent<TSeq> * agent = nullptr;
16271  int pos_in_agent = -99; ///< Location in the agent
16272 
16273  int date = -99;
16274  int id = -99;
16275  std::string tool_name;
16276 
16277  EPI_TYPENAME_TRAITS(TSeq, int) sequence =
16278  EPI_TYPENAME_TRAITS(TSeq, int)(); ///< Sequence of the tool
16279 
16280  std::shared_ptr<ToolFunctions<TSeq>> tool_functions =
16281  std::make_shared< ToolFunctions<TSeq> >();
16282 
16283  epiworld_fast_int state_init = -99;
16284  epiworld_fast_int state_post = -99;
16285 
16286  epiworld_fast_int queue_init = Queue<TSeq>::NoOne; ///< Change of state when added to agent.
16287  epiworld_fast_int queue_post = Queue<TSeq>::NoOne; ///< Change of state when removed from agent.
16288 
16289  void set_agent(Agent<TSeq> * p, size_t idx);
16290 
16291 public:
16292  Tool();
16293  Tool(std::string name = "unknown tool");
16294  Tool(
16295  std::string name,
16296  epiworld_double prevalence,
16297  bool as_proportion
16298  );
16299 
16300  void set_sequence(TSeq d);
16301  void set_sequence(std::shared_ptr<TSeq> d);
16302  EPI_TYPENAME_TRAITS(TSeq, int) get_sequence();
16303 
16313  epiworld_double get_susceptibility_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
16314  epiworld_double get_transmission_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
16315  epiworld_double get_recovery_enhancer(VirusPtr<TSeq> v, Model<TSeq> * model);
16316  epiworld_double get_death_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
16317 
16318  void set_susceptibility_reduction_fun(ToolFun<TSeq> fun);
16319  void set_transmission_reduction_fun(ToolFun<TSeq> fun);
16320  void set_recovery_enhancer_fun(ToolFun<TSeq> fun);
16321  void set_death_reduction_fun(ToolFun<TSeq> fun);
16322 
16323  void set_susceptibility_reduction(epiworld_double * prob);
16324  void set_transmission_reduction(epiworld_double * prob);
16325  void set_recovery_enhancer(epiworld_double * prob);
16326  void set_death_reduction(epiworld_double * prob);
16327 
16328  void set_susceptibility_reduction(epiworld_double prob);
16329  void set_transmission_reduction(epiworld_double prob);
16330  void set_recovery_enhancer(epiworld_double prob);
16331  void set_death_reduction(epiworld_double prob);
16333 
16334  void set_name(std::string name);
16335  std::string get_name() const;
16336 
16337  Agent<TSeq> * get_agent();
16338  int get_id() const;
16339  void set_id(int id);
16340  void set_date(int d);
16341  int get_date() const;
16342 
16343  void set_state(epiworld_fast_int init, epiworld_fast_int post);
16344  void set_queue(epiworld_fast_int init, epiworld_fast_int post);
16345  void get_state(epiworld_fast_int * init, epiworld_fast_int * post);
16346  void get_queue(epiworld_fast_int * init, epiworld_fast_int * post);
16347 
16348  bool operator==(const Tool<TSeq> & other) const;
16349  bool operator!=(const Tool<TSeq> & other) const {return !operator==(other);};
16350 
16351  void print() const;
16352 
16353  void distribute(Model<TSeq> * model);
16354  void set_distribution(ToolToAgentFun<TSeq> fun);
16355 
16356 };
16357 
16358 #endif
16359 /*//////////////////////////////////////////////////////////////////////////////
16361 
16362  End of -include/epiworld/tool-bones.hpp-
16363 
16366 
16367 
16368 /*//////////////////////////////////////////////////////////////////////////////
16370 
16371  Start of -include/epiworld/tool-distribute-meat.hpp-
16372 
16375 
16376 
16377 #ifndef TOOL_DISTRIBUTE_MEAT_HPP
16378 #define TOOL_DISTRIBUTE_MEAT_HPP
16379 
16395 template<typename TSeq = EPI_DEFAULT_TSEQ>
16396 inline ToolToAgentFun<TSeq> distribute_tool_to_set(
16397  std::vector< size_t > agents_ids
16398 ) {
16399 
16400  return [agents_ids](
16401  Tool<TSeq> & tool, Model<TSeq> * model
16402  ) -> void
16403  {
16404  // Adding action
16405  for (auto i: agents_ids)
16406  {
16407  model->get_agent(i).add_tool(
16408  tool,
16409  const_cast<Model<TSeq> * >(model)
16410  );
16411  }
16412  };
16413 
16414 }
16415 
16426 template<typename TSeq = EPI_DEFAULT_TSEQ>
16427 inline ToolToAgentFun<TSeq> distribute_tool_randomly(
16428  epiworld_double prevalence,
16429  bool as_proportion = true,
16430  std::vector< size_t > agents_ids = {}
16431 ) {
16432 
16433  auto agents_ids_ptr = std::make_shared< std::vector< size_t > >(agents_ids);
16434 
16435  return [prevalence,as_proportion,agents_ids_ptr](
16436  Tool<TSeq> & tool, Model<TSeq> * model
16437  ) -> void {
16438 
16439  // Figuring out how what agents are available
16440  bool use_set = agents_ids_ptr->size() > 0;
16441 
16442  // Picking how many
16443  int n_to_distribute;
16444  int n = use_set ?
16445  static_cast<int>(agents_ids_ptr->size()) :
16446  static_cast<int>(model->size());
16447 
16448  if (as_proportion)
16449  {
16450  n_to_distribute = static_cast<int>(std::floor(prevalence * n));
16451 
16452  // Correcting for possible rounding errors
16453  if (n_to_distribute > n)
16454  n_to_distribute = n;
16455 
16456  }
16457  else
16458  {
16459  n_to_distribute = static_cast<int>(prevalence);
16460  }
16461 
16462  if (n_to_distribute > n)
16463  throw std::range_error("There are only " + std::to_string(n) +
16464  " individuals in the population. Cannot add the tool to " + std::to_string(n_to_distribute));
16465 
16466  std::vector< int > idx(n);
16467  std::iota(idx.begin(), idx.end(), 0);
16468  auto & population = model->get_agents();
16469  for (int i = 0u; i < n_to_distribute; ++i)
16470  {
16471  int loc = static_cast<epiworld_fast_uint>(
16472  floor(model->runif() * n--)
16473  );
16474 
16475  if ((loc > 0) && (loc == n))
16476  loc--;
16477 
16478  population[idx[loc]].add_tool(
16479  tool,
16480  const_cast< Model<TSeq> * >(model)
16481  );
16482 
16483  std::swap(idx[loc], idx[n]);
16484 
16485  }
16486 
16487  };
16488 
16489 }
16490 #endif
16491 /*//////////////////////////////////////////////////////////////////////////////
16493 
16494  End of -include/epiworld/tool-distribute-meat.hpp-
16495 
16498 
16499 
16500 /*//////////////////////////////////////////////////////////////////////////////
16502 
16503  Start of -include/epiworld/tool-meat.hpp-
16504 
16507 
16508 
16509 
16510 #ifndef EPIWORLD_TOOLS_MEAT_HPP
16511 #define EPIWORLD_TOOLS_MEAT_HPP
16512 
16521 template<typename TSeq>
16522 inline ToolFun<TSeq> tool_fun_logit(
16523  std::vector< int > vars,
16524  std::vector< double > coefs,
16525  Model<TSeq> * model
16526 ) {
16527 
16528  // Checking that there are features
16529  if (coefs.size() == 0u)
16530  throw std::logic_error(
16531  "The -coefs- argument should feature at least one element."
16532  );
16533 
16534  if (coefs.size() != vars.size())
16535  throw std::length_error(
16536  std::string("The length of -coef- (") +
16537  std::to_string(coefs.size()) +
16538  std::string(") and -vars- (") +
16539  std::to_string(vars.size()) +
16540  std::string(") should match. ")
16541  );
16542 
16543  // Checking that there are variables in the model
16544  if (model != nullptr)
16545  {
16546 
16547  size_t K = model->get_agents_data_ncols();
16548  for (const auto & var: vars)
16549  {
16550  if ((var >= static_cast<int>(K)) | (var < 0))
16551  throw std::range_error(
16552  std::string("The variable ") +
16553  std::to_string(var) +
16554  std::string(" is out of range.") +
16555  std::string(" The agents only feature ") +
16556  std::to_string(K) +
16557  std::string("variables (features).")
16558  );
16559  }
16560 
16561  }
16562 
16563  std::vector< epiworld_double > coefs_f;
16564  for (auto c: coefs)
16565  coefs_f.push_back(static_cast<epiworld_double>(c));
16566 
16567  ToolFun<TSeq> fun_ = [coefs_f,vars](
16568  Tool<TSeq>& tool,
16569  Agent<TSeq> * agent,
16570  VirusPtr<TSeq> virus,
16571  Model<TSeq> * model
16572  ) -> epiworld_double {
16573 
16574  size_t K = coefs_f.size();
16575  epiworld_double res = 0.0;
16576 
16577  #if defined(__OPENMP) || defined(_OPENMP)
16578  #pragma omp simd reduction(+:res)
16579  #endif
16580  for (size_t i = 0u; i < K; ++i)
16581  res += agent->operator[](vars.at(i)) * coefs_f.at(i);
16582 
16583  return 1.0/(1.0 + std::exp(-res));
16584 
16585  };
16586 
16587  return fun_;
16588 
16589 }
16590 
16591 template<typename TSeq>
16592 inline Tool<TSeq>::Tool()
16593 {
16594  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
16595  {
16596  sequence = -1;
16597  }
16598  else
16599  {
16600  sequence = nullptr;
16601  }
16602 
16603  set_name("Tool");
16604 }
16605 
16606 template<typename TSeq>
16607 inline Tool<TSeq>::Tool(std::string name)
16608 {
16609  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
16610  {
16611  sequence = -1;
16612  }
16613  else
16614  {
16615  sequence = nullptr;
16616  }
16617 
16618  set_name(name);
16619 }
16620 
16621 template<typename TSeq>
16622 inline Tool<TSeq>::Tool(
16623  std::string name,
16624  epiworld_double prevalence,
16625  bool as_proportion
16626  )
16627 {
16628 
16629  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
16630  {
16631  sequence = -1;
16632  }
16633  else
16634  {
16635  sequence = nullptr;
16636  }
16637 
16638  set_name(name);
16639 
16640  set_distribution(
16641  distribute_tool_randomly<TSeq>(prevalence, as_proportion)
16642  );
16643 }
16644 
16645 template<typename TSeq>
16646 inline void Tool<TSeq>::set_sequence(TSeq d) {
16647  sequence = std::make_shared<TSeq>(d);
16648 }
16649 
16650 template<typename TSeq>
16651 inline void Tool<TSeq>::set_sequence(std::shared_ptr<TSeq> d) {
16652  sequence = d;
16653 }
16654 
16655 template<>
16656 inline void Tool<int>::set_sequence(int d) {
16657  sequence = d;
16658 }
16659 
16660 template<typename TSeq>
16661 inline EPI_TYPENAME_TRAITS(TSeq, int) Tool<TSeq>::get_sequence() {
16662  return sequence;
16663 }
16664 
16665 template<typename TSeq>
16666 inline epiworld_double Tool<TSeq>::get_susceptibility_reduction(
16667  VirusPtr<TSeq> v,
16668  Model<TSeq> * model
16669 )
16670 {
16671 
16672  if (tool_functions->susceptibility_reduction)
16673  return tool_functions->susceptibility_reduction(
16674  *this, this->agent, v, model
16675  );
16676 
16677  return DEFAULT_TOOL_CONTAGION_REDUCTION;
16678 
16679 }
16680 
16681 template<typename TSeq>
16682 inline epiworld_double Tool<TSeq>::get_transmission_reduction(
16683  VirusPtr<TSeq> v,
16684  Model<TSeq> * model
16685 )
16686 {
16687 
16688  if (tool_functions->transmission_reduction)
16689  return tool_functions->transmission_reduction(
16690  *this, this->agent, v, model
16691  );
16692 
16693  return DEFAULT_TOOL_TRANSMISSION_REDUCTION;
16694 
16695 }
16696 
16697 template<typename TSeq>
16698 inline epiworld_double Tool<TSeq>::get_recovery_enhancer(
16699  VirusPtr<TSeq> v,
16700  Model<TSeq> * model
16701 )
16702 {
16703 
16704  if (tool_functions->recovery_enhancer)
16705  return tool_functions->recovery_enhancer(*this, this->agent, v, model);
16706 
16707  return DEFAULT_TOOL_RECOVERY_ENHANCER;
16708 
16709 }
16710 
16711 template<typename TSeq>
16712 inline epiworld_double Tool<TSeq>::get_death_reduction(
16713  VirusPtr<TSeq> v,
16714  Model<TSeq> * model
16715 )
16716 {
16717 
16718  if (tool_functions->death_reduction)
16719  return tool_functions->death_reduction(*this, this->agent, v, model);
16720 
16721  return DEFAULT_TOOL_DEATH_REDUCTION;
16722 
16723 }
16724 
16725 template<typename TSeq>
16726 inline void Tool<TSeq>::set_susceptibility_reduction_fun(
16727  ToolFun<TSeq> fun
16728 )
16729 {
16730  tool_functions->susceptibility_reduction = fun;
16731 }
16732 
16733 template<typename TSeq>
16734 inline void Tool<TSeq>::set_transmission_reduction_fun(
16735  ToolFun<TSeq> fun
16736 )
16737 {
16738  tool_functions->transmission_reduction = fun;
16739 }
16740 
16741 template<typename TSeq>
16742 inline void Tool<TSeq>::set_recovery_enhancer_fun(
16743  ToolFun<TSeq> fun
16744 )
16745 {
16746  tool_functions->recovery_enhancer = fun;
16747 }
16748 
16749 template<typename TSeq>
16750 inline void Tool<TSeq>::set_death_reduction_fun(
16751  ToolFun<TSeq> fun
16752 )
16753 {
16754  tool_functions->death_reduction = fun;
16755 }
16756 
16757 template<typename TSeq>
16758 inline void Tool<TSeq>::set_susceptibility_reduction(epiworld_double * prob)
16759 {
16760 
16761  ToolFun<TSeq> tmpfun =
16762  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16763  {
16764  return *prob;
16765  };
16766 
16767  tool_functions->susceptibility_reduction = tmpfun;
16768 
16769 }
16770 
16771 // EPIWORLD_SET_LAMBDA(susceptibility_reduction)
16772 template<typename TSeq>
16773 inline void Tool<TSeq>::set_transmission_reduction(epiworld_double * prob)
16774 {
16775 
16776  ToolFun<TSeq> tmpfun =
16777  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16778  {
16779  return *prob;
16780  };
16781 
16782  tool_functions->transmission_reduction = tmpfun;
16783 
16784 }
16785 
16786 // EPIWORLD_SET_LAMBDA(transmission_reduction)
16787 template<typename TSeq>
16788 inline void Tool<TSeq>::set_recovery_enhancer(epiworld_double * prob)
16789 {
16790 
16791  ToolFun<TSeq> tmpfun =
16792  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16793  {
16794  return *prob;
16795  };
16796 
16797  tool_functions->recovery_enhancer = tmpfun;
16798 
16799 }
16800 
16801 // EPIWORLD_SET_LAMBDA(recovery_enhancer)
16802 template<typename TSeq>
16803 inline void Tool<TSeq>::set_death_reduction(epiworld_double * prob)
16804 {
16805 
16806  ToolFun<TSeq> tmpfun =
16807  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16808  {
16809  return *prob;
16810  };
16811 
16812  tool_functions->death_reduction = tmpfun;
16813 
16814 }
16815 
16816 // EPIWORLD_SET_LAMBDA(death_reduction)
16817 
16818 // #undef EPIWORLD_SET_LAMBDA
16819 template<typename TSeq>
16820 inline void Tool<TSeq>::set_susceptibility_reduction(
16821  epiworld_double prob
16822 )
16823 {
16824 
16825  ToolFun<TSeq> tmpfun =
16826  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16827  {
16828  return prob;
16829  };
16830 
16831  tool_functions->susceptibility_reduction = tmpfun;
16832 
16833 }
16834 
16835 template<typename TSeq>
16836 inline void Tool<TSeq>::set_transmission_reduction(
16837  epiworld_double prob
16838 )
16839 {
16840 
16841  ToolFun<TSeq> tmpfun =
16842  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16843  {
16844  return prob;
16845  };
16846 
16847  tool_functions->transmission_reduction = tmpfun;
16848 
16849 }
16850 
16851 template<typename TSeq>
16852 inline void Tool<TSeq>::set_recovery_enhancer(
16853  epiworld_double prob
16854 )
16855 {
16856 
16857  ToolFun<TSeq> tmpfun =
16858  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16859  {
16860  return prob;
16861  };
16862 
16863  tool_functions->recovery_enhancer = tmpfun;
16864 
16865 }
16866 
16867 template<typename TSeq>
16868 inline void Tool<TSeq>::set_death_reduction(
16869  epiworld_double prob
16870 )
16871 {
16872 
16873  ToolFun<TSeq> tmpfun =
16874  [prob](Tool<TSeq> &, Agent<TSeq> *, VirusPtr<TSeq>, Model<TSeq> *)
16875  {
16876  return prob;
16877  };
16878 
16879  tool_functions->death_reduction = tmpfun;
16880 
16881 }
16882 
16883 template<typename TSeq>
16884 inline void Tool<TSeq>::set_name(std::string name)
16885 {
16886  tool_name = name;
16887 }
16888 
16889 template<typename TSeq>
16890 inline std::string Tool<TSeq>::get_name() const {
16891 
16892  return tool_name;
16893 
16894 }
16895 
16896 template<typename TSeq>
16897 inline Agent<TSeq> * Tool<TSeq>::get_agent()
16898 {
16899  return this->agent;
16900 }
16901 
16902 template<typename TSeq>
16903 inline void Tool<TSeq>::set_agent(Agent<TSeq> * p, size_t idx)
16904 {
16905  agent = p;
16906  pos_in_agent = static_cast<int>(idx);
16907 }
16908 
16909 template<typename TSeq>
16910 inline int Tool<TSeq>::get_id() const {
16911  return id;
16912 }
16913 
16914 
16915 template<typename TSeq>
16916 inline void Tool<TSeq>::set_id(int id)
16917 {
16918  this->id = id;
16919 }
16920 
16921 template<typename TSeq>
16922 inline void Tool<TSeq>::set_date(int d)
16923 {
16924  this->date = d;
16925 }
16926 
16927 template<typename TSeq>
16928 inline int Tool<TSeq>::get_date() const
16929 {
16930  return date;
16931 }
16932 
16933 template<typename TSeq>
16934 inline void Tool<TSeq>::set_state(
16935  epiworld_fast_int init,
16936  epiworld_fast_int end
16937 )
16938 {
16939  state_init = init;
16940  state_post = end;
16941 }
16942 
16943 template<typename TSeq>
16944 inline void Tool<TSeq>::set_queue(
16945  epiworld_fast_int init,
16946  epiworld_fast_int end
16947 )
16948 {
16949  queue_init = init;
16950  queue_post = end;
16951 }
16952 
16953 template<typename TSeq>
16954 inline void Tool<TSeq>::get_state(
16955  epiworld_fast_int * init,
16956  epiworld_fast_int * post
16957 )
16958 {
16959  if (init != nullptr)
16960  *init = state_init;
16961 
16962  if (post != nullptr)
16963  *post = state_post;
16964 
16965 }
16966 
16967 template<typename TSeq>
16968 inline void Tool<TSeq>::get_queue(
16969  epiworld_fast_int * init,
16970  epiworld_fast_int * post
16971 )
16972 {
16973  if (init != nullptr)
16974  *init = queue_init;
16975 
16976  if (post != nullptr)
16977  *post = queue_post;
16978 
16979 }
16980 
16981 template<>
16982 inline bool Tool<std::vector<int>>::operator==(
16983  const Tool<std::vector<int>> & other
16984  ) const
16985 {
16986 
16987  if (sequence->size() != other.sequence->size())
16988  return false;
16989 
16990  for (size_t i = 0u; i < sequence->size(); ++i)
16991  {
16992  if (sequence->operator[](i) != other.sequence->operator[](i))
16993  return false;
16994  }
16995 
16996  if (tool_name != other.tool_name)
16997  return false;
16998 
16999  if (state_init != other.state_init)
17000  return false;
17001 
17002  if (state_post != other.state_post)
17003  return false;
17004 
17005  if (queue_init != other.queue_init)
17006  return false;
17007 
17008  if (queue_post != other.queue_post)
17009  return false;
17010 
17011 
17012  return true;
17013 
17014 }
17015 
17016 template<typename TSeq>
17017 inline bool Tool<TSeq>::operator==(const Tool<TSeq> & other) const
17018 {
17019  EPI_IF_TSEQ_LESS_EQ_INT( TSeq )
17020  {
17021  if (sequence != other.sequence)
17022  return false;
17023  }
17024  else
17025  {
17026  if (*sequence != *other.sequence)
17027  return false;
17028  }
17029 
17030 
17031  if (tool_name != other.tool_name)
17032  return false;
17033 
17034  if (state_init != other.state_init)
17035  return false;
17036 
17037  if (state_post != other.state_post)
17038  return false;
17039 
17040  if (queue_init != other.queue_init)
17041  return false;
17042 
17043  if (queue_post != other.queue_post)
17044  return false;
17045 
17046  return true;
17047 
17048 }
17049 
17050 
17051 template<typename TSeq>
17052 inline void Tool<TSeq>::print() const
17053 {
17054 
17055  printf_epiworld("Tool : %s\n", tool_name.c_str());
17056  printf_epiworld("Id : %s\n", (id < 0)? std::string("(empty)").c_str() : std::to_string(id).c_str());
17057  printf_epiworld("state_init : %i\n", static_cast<int>(state_init));
17058  printf_epiworld("state_post : %i\n", static_cast<int>(state_post));
17059  printf_epiworld("queue_init : %i\n", static_cast<int>(queue_init));
17060  printf_epiworld("queue_post : %i\n", static_cast<int>(queue_post));
17061 
17062 }
17063 
17064 template<typename TSeq>
17065 inline void Tool<TSeq>::distribute(Model<TSeq> * model)
17066 {
17067 
17068  if (tool_functions->dist)
17069  {
17070 
17071  tool_functions->dist(*this, model);
17072 
17073  }
17074 
17075 }
17076 
17077 template<typename TSeq>
17078 inline void Tool<TSeq>::set_distribution(ToolToAgentFun<TSeq> fun)
17079 {
17080  tool_functions->dist = fun;
17081 }
17082 
17083 #endif
17084 /*//////////////////////////////////////////////////////////////////////////////
17086 
17087  End of -include/epiworld/tool-meat.hpp-
17088 
17091 
17092 
17093 
17094 /*//////////////////////////////////////////////////////////////////////////////
17096 
17097  Start of -include/epiworld/entity-bones.hpp-
17098 
17101 
17102 
17103 #ifndef EPIWORLD_ENTITY_BONES_HPP
17104 #define EPIWORLD_ENTITY_BONES_HPP
17105 
17106 template<typename TSeq>
17107 class Model;
17108 
17109 template<typename TSeq>
17110 class Agent;
17111 
17112 template<typename TSeq>
17113 class AgentsSample;
17114 
17115 template<typename TSeq>
17116 inline void default_add_entity(Event<TSeq> & a, Model<TSeq> * m);
17117 
17118 template<typename TSeq>
17119 inline void default_rm_entity(Event<TSeq> & a, Model<TSeq> * m);
17120 
17121 template<typename TSeq>
17122 class Entity {
17123  friend class Agent<TSeq>;
17124  friend class AgentsSample<TSeq>;
17125  friend class Model<TSeq>;
17126  friend void default_add_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
17127  friend void default_rm_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
17128 private:
17129 
17130  int id = -1;
17131  std::vector< size_t > agents; ///< Vector of agents
17132  std::vector< size_t > agents_location; ///< Location where the entity is stored in the agent
17133  size_t n_agents = 0u;
17134 
17135  int max_capacity = -1;
17136  std::string entity_name = "Unnamed entity";
17137 
17138  std::vector< epiworld_double > location = {0.0}; ///< An arbitrary vector for location
17139 
17140  epiworld_fast_int state_init = -99;
17141  epiworld_fast_int state_post = -99;
17142 
17143  epiworld_fast_int queue_init = 0; ///< Change of state when added to agent.
17144  epiworld_fast_int queue_post = 0; ///< Change of state when removed from agent.
17145 
17146  EntityToAgentFun<TSeq> dist_fun = nullptr;
17147 
17148 public:
17149 
17150 
17159  Entity(
17160  std::string name,
17161  EntityToAgentFun<TSeq> fun = nullptr
17162  ) :
17163  entity_name(name),
17164  dist_fun(fun)
17165  {};
17166 
17167  void add_agent(Agent<TSeq> & p, Model<TSeq> * model);
17168  void add_agent(Agent<TSeq> * p, Model<TSeq> * model);
17169  void rm_agent(size_t idx, Model<TSeq> * model);
17170  size_t size() const noexcept;
17171  void set_location(std::vector< epiworld_double > loc);
17172  std::vector< epiworld_double > & get_location();
17173 
17174  typename std::vector< size_t >::iterator begin();
17175  typename std::vector< size_t >::iterator end();
17176 
17177  typename std::vector< size_t >::const_iterator begin() const;
17178  typename std::vector< size_t >::const_iterator end() const;
17179 
17180  size_t operator[](size_t i);
17181 
17182  int get_id() const noexcept;
17183  const std::string & get_name() const noexcept;
17184 
17185  void set_state(epiworld_fast_int init, epiworld_fast_int post);
17186  void set_queue(epiworld_fast_int init, epiworld_fast_int post);
17187  void get_state(epiworld_fast_int * init, epiworld_fast_int * post);
17188  void get_queue(epiworld_fast_int * init, epiworld_fast_int * post);
17189 
17190  void reset();
17191 
17192  bool operator==(const Entity<TSeq> & other) const;
17193  bool operator!=(const Entity<TSeq> & other) const {return !operator==(other);};
17194 
17202  void distribute(Model<TSeq> * model);
17203 
17204  std::vector< size_t > & get_agents();
17205 
17206  void print() const;
17207  void set_distribution(EntityToAgentFun<TSeq> fun);
17208 
17209 };
17210 
17211 
17212 #endif
17213 /*//////////////////////////////////////////////////////////////////////////////
17215 
17216  End of -include/epiworld/entity-bones.hpp-
17217 
17220 
17221 
17222 /*//////////////////////////////////////////////////////////////////////////////
17224 
17225  Start of -include/epiworld/entity-distribute-meat.hpp-
17226 
17229 
17230 
17231 #ifndef EPIWORLD_ENTITY_DISTRIBUTE_MEAT_HPP
17232 #define EPIWORLD_ENTITY_DISTRIBUTE_MEAT_HPP
17233 
17234 
17235 template <typename TSeq = EPI_DEFAULT_TSEQ>
17246 inline EntityToAgentFun<TSeq> distribute_entity_randomly(
17247  epiworld_double prevalence,
17248  bool as_proportion,
17249  bool to_unassigned
17250 )
17251 {
17252 
17253  return [prevalence, as_proportion, to_unassigned](
17254  Entity<TSeq> & e, Model<TSeq> * m
17255  ) -> void {
17256 
17257 
17258  // Preparing the sampling space
17259  std::vector< size_t > idx;
17260  if (to_unassigned)
17261  {
17262  for (const auto & a: m->get_agents())
17263  if (a.get_n_entities() == 0)
17264  idx.push_back(a.get_id());
17265  }
17266  else
17267  {
17268 
17269  for (const auto & a: m->get_agents())
17270  idx.push_back(a.get_id());
17271 
17272  }
17273 
17274  size_t n = idx.size();
17275 
17276  // Figuring out how many to sample
17277  int n_to_sample;
17278  if (as_proportion)
17279  {
17280  n_to_sample = static_cast<int>(std::floor(prevalence * n));
17281 
17282  // Correcting for possible overflow
17283  if (n_to_sample > static_cast<int>(n))
17284  n_to_sample = static_cast<int>(n);
17285 
17286  } else
17287  {
17288  n_to_sample = static_cast<int>(prevalence);
17289  if (n_to_sample > static_cast<int>(n))
17290  throw std::range_error("There are only " + std::to_string(n) +
17291  " individuals in the population. Cannot add the entity to " +
17292  std::to_string(n_to_sample));
17293  }
17294 
17295  int n_left = n;
17296  for (int i = 0; i < n_to_sample; ++i)
17297  {
17298  int loc = static_cast<epiworld_fast_uint>(
17299  floor(m->runif() * n_left--)
17300  );
17301 
17302  // Correcting for possible overflow
17303  if ((loc > 0) && (loc >= n_left))
17304  loc = n_left - 1;
17305 
17306  m->get_agent(idx[loc]).add_entity(e, m);
17307 
17308  std::swap(idx[loc], idx[n_left]);
17309 
17310  }
17311 
17312  };
17313 
17314 }
17315 
17316 template<typename TSeq = EPI_DEFAULT_TSEQ>
17327 inline EntityToAgentFun<TSeq> distribute_entity_to_range(
17328  int from,
17329  int to,
17330  bool to_unassigned = false
17331  ) {
17332 
17333  if (to_unassigned)
17334  {
17335 
17336  return [from, to](Entity<TSeq> & e, Model<TSeq> * m) -> void {
17337 
17338  auto & agents = m->get_agents();
17339  for (size_t i = from; i < to; ++i)
17340  {
17341  if (agents[i].get_n_entities() == 0)
17342  e.add_agent(&agents[i], m);
17343  else
17344  throw std::logic_error(
17345  "Agent " + std::to_string(i) + " already has an entity."
17346  );
17347  }
17348 
17349  return;
17350 
17351  };
17352 
17353  }
17354  else
17355  {
17356 
17357  return [from, to](Entity<TSeq> & e, Model<TSeq> * m) -> void {
17358 
17359  auto & agents = m->get_agents();
17360  for (size_t i = from; i < to; ++i)
17361  {
17362  e.add_agent(&agents[i], m);
17363  }
17364 
17365  return;
17366 
17367  };
17368 
17369  }
17370 }
17371 
17372 
17373 template<typename TSeq = EPI_DEFAULT_TSEQ>
17374 inline EntityToAgentFun<TSeq> distribute_entity_to_set(
17375  std::vector< size_t > & idx
17376  ) {
17377 
17378  auto idx_shared = std::make_shared< std::vector< size_t > >(idx);
17379 
17380  return [idx_shared](Entity<TSeq> & e, Model<TSeq> * m) -> void {
17381 
17382  for (const auto & i: *idx_shared)
17383  {
17384  e.add_agent(&m->get_agent(i), m);
17385  }
17386 
17387  };
17388 
17389 }
17390 
17391 #endif
17392 /*//////////////////////////////////////////////////////////////////////////////
17394 
17395  End of -include/epiworld/entity-distribute-meat.hpp-
17396 
17399 
17400 
17401 /*//////////////////////////////////////////////////////////////////////////////
17403 
17404  Start of -include/epiworld/entity-meat.hpp-
17405 
17408 
17409 
17410 #ifndef EPIWORLD_ENTITY_MEAT_HPP
17411 #define EPIWORLD_ENTITY_MEAT_HPP
17412 
17413 template<typename TSeq>
17414 inline void Entity<TSeq>::add_agent(
17415  Agent<TSeq> & p,
17416  Model<TSeq> * model
17417  )
17418 {
17419 
17420  // Need to add it to the events, through the individual
17421  p.add_entity(*this, model);
17422 
17423 }
17424 
17425 template<typename TSeq>
17426 inline void Entity<TSeq>::add_agent(
17427  Agent<TSeq> * p,
17428  Model<TSeq> * model
17429  )
17430 {
17431  p->add_entity(*this, model);
17432 }
17433 
17434 template<typename TSeq>
17435 inline void Entity<TSeq>::rm_agent(size_t idx, Model<TSeq> * model)
17436 {
17437  if (idx >= n_agents)
17438  throw std::out_of_range(
17439  "Trying to remove agent "+ std::to_string(idx) +
17440  " out of " + std::to_string(n_agents)
17441  );
17442 
17443  model->get_agents()[agents[idx]].rm_entity(*this, model);
17444 
17445  return;
17446 }
17447 
17448 template<typename TSeq>
17449 inline size_t Entity<TSeq>::size() const noexcept
17450 {
17451  return n_agents;
17452 }
17453 
17454 template<typename TSeq>
17455 inline void Entity<TSeq>::set_location(std::vector< epiworld_double > loc)
17456 {
17457  location = loc;
17458 }
17459 
17460 template<typename TSeq>
17461 inline std::vector< epiworld_double > & Entity<TSeq>::get_location()
17462 {
17463  return location;
17464 }
17465 
17466 template<typename TSeq>
17467 inline typename std::vector< size_t >::iterator Entity<TSeq>::begin()
17468 {
17469 
17470  if (n_agents == 0)
17471  return typename std::vector< size_t >::iterator{};
17472 
17473  return agents.begin();
17474 
17475 }
17476 
17477 template<typename TSeq>
17478 inline typename std::vector< size_t >::iterator Entity<TSeq>::end()
17479 {
17480  if (n_agents == 0)
17481  return typename std::vector< size_t >::iterator{};
17482 
17483  return agents.begin() + n_agents;
17484 }
17485 
17486 template<typename TSeq>
17487 inline typename std::vector< size_t >::const_iterator Entity<TSeq>::begin() const
17488 {
17489 
17490  if (n_agents == 0)
17491  return typename std::vector< size_t >::const_iterator{};
17492 
17493  return agents.begin();
17494 
17495 }
17496 
17497 template<typename TSeq>
17498 inline typename std::vector< size_t >::const_iterator Entity<TSeq>::end() const
17499 {
17500  if (n_agents == 0)
17501  return typename std::vector< size_t >::const_iterator{};
17502 
17503  return agents.begin() + n_agents;
17504 }
17505 
17506 template<typename TSeq>
17507 size_t Entity<TSeq>::operator[](size_t i)
17508 {
17509  if (n_agents <= i)
17510  throw std::logic_error(
17511  "There are not that many agents in this entity. " +
17512  std::to_string(n_agents) + " <= " + std::to_string(i)
17513  );
17514 
17515  return i;
17516 }
17517 
17518 template<typename TSeq>
17519 inline int Entity<TSeq>::get_id() const noexcept
17520 {
17521  return id;
17522 }
17523 
17524 template<typename TSeq>
17525 inline const std::string & Entity<TSeq>::get_name() const noexcept
17526 {
17527  return entity_name;
17528 }
17529 
17530 template<typename TSeq>
17531 inline void Entity<TSeq>::set_state(
17532  epiworld_fast_int init,
17533  epiworld_fast_int end
17534 )
17535 {
17536  state_init = init;
17537  state_post = end;
17538 }
17539 
17540 template<typename TSeq>
17541 inline void Entity<TSeq>::set_queue(
17542  epiworld_fast_int init,
17543  epiworld_fast_int end
17544 )
17545 {
17546  queue_init = init;
17547  queue_post = end;
17548 }
17549 
17550 template<typename TSeq>
17551 inline void Entity<TSeq>::get_state(
17552  epiworld_fast_int * init,
17553  epiworld_fast_int * post
17554 )
17555 {
17556  if (init != nullptr)
17557  *init = state_init;
17558 
17559  if (post != nullptr)
17560  *post = state_post;
17561 
17562 }
17563 
17564 template<typename TSeq>
17565 inline void Entity<TSeq>::get_queue(
17566  epiworld_fast_int * init,
17567  epiworld_fast_int * post
17568 )
17569 {
17570  if (init != nullptr)
17571  *init = queue_init;
17572 
17573  if (post != nullptr)
17574  *post = queue_post;
17575 
17576 }
17577 
17578 template<typename TSeq>
17579 inline void Entity<TSeq>::reset()
17580 {
17581 
17582  this->agents.clear();
17583  this->n_agents = 0u;
17584  this->agents_location.clear();
17585 
17586  return;
17587 
17588 }
17589 
17590 template<typename TSeq>
17591 inline bool Entity<TSeq>::operator==(const Entity<TSeq> & other) const
17592 {
17593 
17594  if (id != other.id)
17595  return false;
17596 
17597  if (n_agents != other.n_agents)
17598  return false;
17599 
17600  for (size_t i = 0u; i < n_agents; ++i)
17601  {
17602  if (agents[i] != other.agents[i])
17603  return false;
17604  }
17605 
17606 
17607  if (max_capacity != other.max_capacity)
17608  return false;
17609 
17610  if (entity_name != other.entity_name)
17611  return false;
17612 
17613  if (location.size() != other.location.size())
17614  return false;
17615 
17616  for (size_t i = 0u; i < location.size(); ++i)
17617  {
17618 
17619  if (location[i] != other.location[i])
17620  return false;
17621 
17622  }
17623 
17624  if (state_init != other.state_init)
17625  return false;
17626 
17627  if (state_post != other.state_post)
17628  return false;
17629 
17630  if (queue_init != other.queue_init)
17631  return false;
17632 
17633  if (queue_post != other.queue_post)
17634  return false;
17635 
17636  return true;
17637 
17638 }
17639 
17640 template<typename TSeq>
17641 inline void Entity<TSeq>::distribute(Model<TSeq> * model)
17642 {
17643 
17644  if (dist_fun)
17645  {
17646 
17647  dist_fun(*this, model);
17648 
17649  }
17650 
17651 }
17652 
17653 template<typename TSeq>
17654 inline std::vector< size_t > & Entity<TSeq>::get_agents()
17655 {
17656  return agents;
17657 }
17658 
17659 template<typename TSeq>
17660 inline void Entity<TSeq>::print() const
17661 {
17662 
17663  printf_epiworld(
17664  "Entity '%s' (id %i) with %i agents.\n",
17665  this->entity_name.c_str(),
17666  static_cast<int>(id),
17667  static_cast<int>(n_agents)
17668  );
17669 }
17670 
17671 template<typename TSeq>
17672 inline void Entity<TSeq>::set_distribution(EntityToAgentFun<TSeq> fun)
17673 {
17674  dist_fun = fun;
17675 }
17676 
17677 #endif
17678 /*//////////////////////////////////////////////////////////////////////////////
17680 
17681  End of -include/epiworld/entity-meat.hpp-
17682 
17685 
17686 
17687 
17688 /*//////////////////////////////////////////////////////////////////////////////
17690 
17691  Start of -include/epiworld/entities-bones.hpp-
17692 
17695 
17696 
17697 #ifndef EPIWORLD_ENTITIES_BONES_HPP
17698 #define EPIWORLD_ENTITIES_BONES_HPP
17699 
17700 template<typename TSeq>
17701 class Virus;
17702 
17703 template<typename TSeq>
17704 class Agent;
17705 
17706 
17712 template<typename TSeq>
17713 class Entities {
17714  friend class Entity<TSeq>;
17715  friend class Agent<TSeq>;
17716 private:
17717  std::vector< Entity<TSeq> * > dat;
17718  const size_t n_entities;
17719 
17720 public:
17721 
17722  Entities() = delete;
17723  Entities(Agent<TSeq> & p);
17724 
17725  typename std::vector< Entity<TSeq> * >::iterator begin();
17726  typename std::vector< Entity<TSeq> * >::iterator end();
17727 
17728  Entity<TSeq> & operator()(size_t i);
17729  Entity<TSeq> & operator[](size_t i);
17730 
17731  size_t size() const noexcept;
17732 
17733  bool operator==(const Entities<TSeq> & other) const;
17734 
17735 };
17736 
17737 template<typename TSeq>
17738 inline Entities<TSeq>::Entities(Agent<TSeq> & p) :
17739  n_entities(p.get_n_entities())
17740 {
17741 
17742  dat.reserve(n_entities);
17743  for (size_t i = 0u; i < n_entities; ++i)
17744  dat.push_back(&p.get_entity(i));
17745 
17746 }
17747 
17748 template<typename TSeq>
17749 inline typename std::vector< Entity<TSeq>* >::iterator Entities<TSeq>::begin()
17750 {
17751 
17752  if (n_entities == 0u)
17753  return dat.end();
17754 
17755  return dat.begin();
17756 }
17757 
17758 template<typename TSeq>
17759 inline typename std::vector< Entity<TSeq>* >::iterator Entities<TSeq>::end()
17760 {
17761 
17762  return begin() + n_entities;
17763 }
17764 
17765 template<typename TSeq>
17766 inline Entity<TSeq> & Entities<TSeq>::operator()(size_t i)
17767 {
17768 
17769  if (i >= n_entities)
17770  throw std::range_error("Entity index out of range.");
17771 
17772  return *dat[i];
17773 
17774 }
17775 
17776 template<typename TSeq>
17777 inline Entity<TSeq> & Entities<TSeq>::operator[](size_t i)
17778 {
17779 
17780  return *dat[i];
17781 
17782 }
17783 
17784 template<typename TSeq>
17785 inline size_t Entities<TSeq>::size() const noexcept
17786 {
17787  return n_entities;
17788 }
17789 
17790 template<typename TSeq>
17791 inline bool Entities<TSeq>::operator==(const Entities<TSeq> & other) const
17792 {
17793 
17794  if (n_entities != other.n_entities)
17795  return false;
17796 
17797  for (size_t i = 0u; i < dat.size(); ++i)
17798  {
17799  if (dat[i] != other.dat[i])
17800  return false;
17801  }
17802 
17803  return true;
17804 }
17805 
17811 template<typename TSeq>
17812 class Entities_const {
17813  friend class Virus<TSeq>;
17814  friend class Agent<TSeq>;
17815 private:
17816  const std::vector< Entity<TSeq>* > dat;
17817  const size_t n_entities;
17818 
17819 public:
17820 
17821  Entities_const() = delete;
17822  Entities_const(const Agent<TSeq> & p);
17823 
17824  typename std::vector< Entity<TSeq>* >::const_iterator begin();
17825  typename std::vector< Entity<TSeq>* >::const_iterator end();
17826 
17827  const Entity<TSeq> & operator()(size_t i);
17828  const Entity<TSeq> & operator[](size_t i);
17829 
17830  size_t size() const noexcept;
17831 
17832  bool operator==(const Entities_const<TSeq> & other) const;
17833 
17834 };
17835 
17836 template<typename TSeq>
17837 inline Entities_const<TSeq>::Entities_const(const Agent<TSeq> & p) :
17838  n_entities(p.get_n_entities())
17839 {
17840 
17841  dat.reserve(n_entities);
17842  for (size_t i = 0u; i < n_entities; ++i)
17843  dat.push_back(&p.get_entity(i));
17844 
17845 }
17846 
17847 template<typename TSeq>
17848 inline typename std::vector< Entity<TSeq>* >::const_iterator Entities_const<TSeq>::begin() {
17849 
17850  if (n_entities == 0u)
17851  return dat.end();
17852 
17853  return dat.begin();
17854 }
17855 
17856 template<typename TSeq>
17857 inline typename std::vector< Entity<TSeq>* >::const_iterator Entities_const<TSeq>::end() {
17858 
17859  return begin() + n_entities;
17860 }
17861 
17862 template<typename TSeq>
17863 inline const Entity<TSeq> & Entities_const<TSeq>::operator()(size_t i)
17864 {
17865 
17866  if (i >= n_entities)
17867  throw std::range_error("Entity index out of range.");
17868 
17869  return *dat[i];
17870 
17871 }
17872 
17873 template<typename TSeq>
17874 inline const Entity<TSeq> & Entities_const<TSeq>::operator[](size_t i)
17875 {
17876 
17877  return *dat[i];
17878 
17879 }
17880 
17881 template<typename TSeq>
17882 inline size_t Entities_const<TSeq>::size() const noexcept
17883 {
17884  return n_entities;
17885 }
17886 
17887 template<typename TSeq>
17888 inline bool Entities_const<TSeq>::operator==(const Entities_const<TSeq> & other) const
17889 {
17890 
17891  if (n_entities != other.n_entities)
17892  return false;
17893 
17894  for (size_t i = 0u; i < dat.size(); ++i)
17895  {
17896  if (dat[i] != other.dat[i])
17897  return false;
17898  }
17899 
17900  return true;
17901 }
17902 
17903 
17904 #endif
17905 /*//////////////////////////////////////////////////////////////////////////////
17907 
17908  End of -include/epiworld/entities-bones.hpp-
17909 
17912 
17913 
17914 
17915 /*//////////////////////////////////////////////////////////////////////////////
17917 
17918  Start of -include/epiworld/agent-meat-virus-sampling.hpp-
17919 
17922 
17923 
17924 #ifndef EPIWORLD_AGENT_MEAT_VIRUS_SAMPLING
17925 #define EPIWORLD_AGENT_MEAT_VIRUS_SAMPLING
17926 
17931 namespace sampler {
17932 
17946 template<typename TSeq = EPI_DEFAULT_TSEQ>
17947 inline std::function<void(Agent<TSeq>*,Model<TSeq>*)> make_update_susceptible(
17948  std::vector< epiworld_fast_uint > exclude = {}
17949  )
17950 {
17951 
17952 
17953  if (exclude.size() == 0u)
17954  {
17955 
17956  std::function<void(Agent<TSeq>*,Model<TSeq>*)> sampler =
17957  [](Agent<TSeq> * p, Model<TSeq> * m) -> void
17958  {
17959 
17960  if (p->get_virus() != nullptr)
17961  throw std::logic_error(
17962  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
17963  std::string("Agent id ") + std::to_string(p->get_id()) +
17964  std::string(" has a virus.")
17965  );
17966 
17967  // This computes the prob of getting any neighbor variant
17968  size_t nviruses_tmp = 0u;
17969  for (auto & neighbor: p->get_neighbors())
17970  {
17971 
17972  auto & v = neighbor->get_virus();
17973  if (v == nullptr)
17974  continue;
17975 
17976  /* And it is a function of susceptibility_reduction as well */
17977  m->array_double_tmp[nviruses_tmp] =
17978  (1.0 - p->get_susceptibility_reduction(v, m)) *
17979  v->get_prob_infecting(m) *
17980  (1.0 - neighbor->get_transmission_reduction(v, m))
17981  ;
17982 
17983  m->array_virus_tmp[nviruses_tmp++] = &(*v);
17984 
17985  }
17986 
17987  // No virus to compute
17988  if (nviruses_tmp == 0u)
17989  return;
17990 
17991  // Running the roulette
17992  int which = roulette(nviruses_tmp, m);
17993 
17994  if (which < 0)
17995  return;
17996 
17997  p->set_virus(*m->array_virus_tmp[which], m);
17998 
17999  return;
18000  };
18001 
18002  return sampler;
18003 
18004  } else {
18005 
18006  // Making room for the query
18007  std::shared_ptr<std::vector<bool>> exclude_agent_bool =
18008  std::make_shared<std::vector<bool>>(0);
18009 
18010  std::shared_ptr<std::vector<epiworld_fast_uint>> exclude_agent_bool_idx =
18011  std::make_shared<std::vector<epiworld_fast_uint>>(exclude);
18012 
18013  std::function<void(Agent<TSeq>*,Model<TSeq>*)> sampler =
18014  [exclude_agent_bool,exclude_agent_bool_idx](Agent<TSeq> * p, Model<TSeq> * m) -> void
18015  {
18016 
18017  // The first time we call it, we need to initialize the vector
18018  if (exclude_agent_bool->size() == 0u)
18019  {
18020 
18021  exclude_agent_bool->resize(m->get_states().size(), false);
18022  for (auto s : *exclude_agent_bool_idx)
18023  {
18024  if (s >= exclude_agent_bool->size())
18025  throw std::logic_error(
18026  std::string("You are trying to exclude a state that is out of range: ") +
18027  std::to_string(s) + std::string(". There are only ") +
18028  std::to_string(exclude_agent_bool->size()) +
18029  std::string(" states in the model.")
18030  );
18031 
18032  exclude_agent_bool->operator[](s) = true;
18033 
18034  }
18035 
18036  }
18037 
18038  if (p->get_virus() != nullptr)
18039  throw std::logic_error(
18040  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
18041  std::string("Agent id ") + std::to_string(p->get_id()) +
18042  std::string(" has a virus.")
18043  );
18044 
18045  // This computes the prob of getting any neighbor variant
18046  size_t nviruses_tmp = 0u;
18047  for (auto & neighbor: p->get_neighbors())
18048  {
18049 
18050  // If the state is in the list, exclude it
18051  if (exclude_agent_bool->operator[](neighbor->get_state()))
18052  continue;
18053 
18054  auto & v = neighbor->get_virus();
18055  if (v == nullptr)
18056  continue;
18057 
18058 
18059  /* And it is a function of susceptibility_reduction as well */
18060  m->array_double_tmp[nviruses_tmp] =
18061  (1.0 - p->get_susceptibility_reduction(v, m)) *
18062  v->get_prob_infecting(m) *
18063  (1.0 - neighbor->get_transmission_reduction(v, m))
18064  ;
18065 
18066  m->array_virus_tmp[nviruses_tmp++] = &(*v);
18067 
18068  }
18069 
18070  // No virus to compute
18071  if (nviruses_tmp == 0u)
18072  return;
18073 
18074  // Running the roulette
18075  int which = roulette(nviruses_tmp, m);
18076 
18077  if (which < 0)
18078  return;
18079 
18080  p->set_virus(*m->array_virus_tmp[which], m);
18081 
18082  return;
18083 
18084  };
18085 
18086  return sampler;
18087 
18088  }
18089 
18090 }
18091 
18105 template<typename TSeq = EPI_DEFAULT_TSEQ>
18106 inline std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> make_sample_virus_neighbors(
18107  std::vector< epiworld_fast_uint > exclude = {}
18108 )
18109 {
18110  if (exclude.size() == 0u)
18111  {
18112 
18113  std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> res =
18114  [](Agent<TSeq> * p, Model<TSeq> * m) -> Virus<TSeq>* {
18115 
18116  if (p->get_virus() != nullptr)
18117  throw std::logic_error(
18118  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
18119  std::string("Agent id ") + std::to_string(p->get_id()) +
18120  std::string(" has a virus.")
18121  );
18122 
18123  // This computes the prob of getting any neighbor variant
18124  size_t nviruses_tmp = 0u;
18125  for (auto & neighbor: p->get_neighbors())
18126  {
18127 
18128  if (neighbor->get_virus() == nullptr)
18129  continue;
18130 
18131  auto & v = neighbor->get_virus();
18132 
18133  #ifdef EPI_DEBUG
18134  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
18135  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
18136  #endif
18137 
18138  /* And it is a function of susceptibility_reduction as well */
18139  m->array_double_tmp[nviruses_tmp] =
18140  (1.0 - p->get_susceptibility_reduction(v, m)) *
18141  v->get_prob_infecting(m) *
18142  (1.0 - neighbor->get_transmission_reduction(v, m))
18143  ;
18144 
18145  m->array_virus_tmp[nviruses_tmp++] = &(*v);
18146 
18147  }
18148 
18149  // No virus to compute
18150  if (nviruses_tmp == 0u)
18151  return nullptr;
18152 
18153  // Running the roulette
18154  int which = roulette(nviruses_tmp, m);
18155 
18156  if (which < 0)
18157  return nullptr;
18158 
18159  return m->array_virus_tmp[which];
18160 
18161  };
18162 
18163  return res;
18164 
18165 
18166  } else {
18167 
18168  // Making room for the query
18169  std::shared_ptr<std::vector<bool>> exclude_agent_bool =
18170  std::make_shared<std::vector<bool>>(0);
18171 
18172  std::shared_ptr<std::vector<epiworld_fast_uint>> exclude_agent_bool_idx =
18173  std::make_shared<std::vector<epiworld_fast_uint>>(exclude);
18174 
18175 
18176  std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> res =
18177  [exclude_agent_bool,exclude_agent_bool_idx](Agent<TSeq> * p, Model<TSeq> * m) -> Virus<TSeq>* {
18178 
18179  // The first time we call it, we need to initialize the vector
18180  if (exclude_agent_bool->size() == 0u)
18181  {
18182 
18183  exclude_agent_bool->resize(m->get_states().size(), false);
18184  for (auto s : *exclude_agent_bool_idx)
18185  {
18186  if (s >= exclude_agent_bool->size())
18187  throw std::logic_error(
18188  std::string("You are trying to exclude a state that is out of range: ") +
18189  std::to_string(s) + std::string(". There are only ") +
18190  std::to_string(exclude_agent_bool->size()) +
18191  std::string(" states in the model.")
18192  );
18193 
18194  exclude_agent_bool->operator[](s) = true;
18195 
18196  }
18197 
18198  }
18199 
18200  if (p->get_virus() != nullptr)
18201  throw std::logic_error(
18202  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
18203  std::string("Agent id ") + std::to_string(p->get_id()) +
18204  std::string(" has a virus.")
18205  );
18206 
18207  // This computes the prob of getting any neighbor variant
18208  size_t nviruses_tmp = 0u;
18209  for (auto & neighbor: p->get_neighbors())
18210  {
18211 
18212  // If the state is in the list, exclude it
18213  if (exclude_agent_bool->operator[](neighbor->get_state()))
18214  continue;
18215 
18216  if (neighbor->get_virus() == nullptr)
18217  continue;
18218 
18219  auto & v = neighbor->get_virus();
18220 
18221  #ifdef EPI_DEBUG
18222  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
18223  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
18224  #endif
18225 
18226  /* And it is a function of susceptibility_reduction as well */
18227  m->array_double_tmp[nviruses_tmp] =
18228  (1.0 - p->get_susceptibility_reduction(v, m)) *
18229  v->get_prob_infecting(m) *
18230  (1.0 - neighbor->get_transmission_reduction(v, m))
18231  ;
18232 
18233  m->array_virus_tmp[nviruses_tmp++] = &(*v);
18234 
18235  }
18236 
18237  // No virus to compute
18238  if (nviruses_tmp == 0u)
18239  return nullptr;
18240 
18241  // Running the roulette
18242  int which = roulette(nviruses_tmp, m);
18243 
18244  if (which < 0)
18245  return nullptr;
18246 
18247  return m->array_virus_tmp[which];
18248 
18249  };
18250 
18251  return res;
18252 
18253  }
18254 
18255 }
18256 
18273 template<typename TSeq = EPI_DEFAULT_TSEQ>
18275 {
18276 
18277  if (p->get_virus() != nullptr)
18278  throw std::logic_error(
18279  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense!") +
18280  std::string("Agent id ") + std::to_string(p->get_id()) +
18281  std::string(" has a virus.")
18282  );
18283 
18284  // This computes the prob of getting any neighbor variant
18285  size_t nviruses_tmp = 0u;
18286  for (auto & neighbor: p->get_neighbors())
18287  {
18288  #ifdef EPI_DEBUG
18289  int _vcount_neigh = 0;
18290  #endif
18291 
18292  if (neighbor->get_virus() == nullptr)
18293  continue;
18294 
18295  auto & v = neighbor->get_virus();
18296 
18297  #ifdef EPI_DEBUG
18298  if (nviruses_tmp >= m->array_virus_tmp.size())
18299  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
18300  #endif
18301 
18302  /* And it is a function of susceptibility_reduction as well */
18303  m->array_double_tmp[nviruses_tmp] =
18304  (1.0 - p->get_susceptibility_reduction(v, m)) *
18305  v->get_prob_infecting(m) *
18306  (1.0 - neighbor->get_transmission_reduction(v, m))
18307  ;
18308 
18309  m->array_virus_tmp[nviruses_tmp++] = &(*v);
18310 
18311  #ifdef EPI_DEBUG
18312  if (
18313  (m->array_double_tmp[nviruses_tmp - 1] < 0.0) |
18314  (m->array_double_tmp[nviruses_tmp - 1] > 1.0)
18315  )
18316  {
18317  printf_epiworld(
18318  "[epi-debug] Agent %i's virus %i has transmission prob outside of [0, 1]: %.4f!\n",
18319  static_cast<int>(neighbor->get_id()),
18320  static_cast<int>(_vcount_neigh++),
18321  m->array_double_tmp[nviruses_tmp - 1]
18322  );
18323  }
18324  #endif
18325 
18326  }
18327 
18328 
18329  // No virus to compute
18330  if (nviruses_tmp == 0u)
18331  return nullptr;
18332 
18333  #ifdef EPI_DEBUG
18334  m->get_db().n_transmissions_potential++;
18335  #endif
18336 
18337  // Running the roulette
18338  int which = roulette(nviruses_tmp, m);
18339 
18340  if (which < 0)
18341  return nullptr;
18342 
18343  #ifdef EPI_DEBUG
18344  m->get_db().n_transmissions_today++;
18345  #endif
18346 
18347  return m->array_virus_tmp[which];
18348 
18349 }
18350 
18351 }
18352 
18353 #endif
18354 /*//////////////////////////////////////////////////////////////////////////////
18356 
18357  End of -include/epiworld/agent-meat-virus-sampling.hpp-
18358 
18361 
18362 
18363 /*//////////////////////////////////////////////////////////////////////////////
18365 
18366  Start of -include/epiworld/agent-meat-state.hpp-
18367 
18370 
18371 
18372 #ifndef EPIWORLD_PERSON_MEAT_STATE_HPP
18373 #define EPIWORLD_PERSON_MEAT_STATE_HPP
18374 
18375 /*//////////////////////////////////////////////////////////////////////////////
18377 
18378  Start of -include/epiworld/model-bones.hpp-
18379 
18382 
18383 
18384 #ifndef EPIWORLD_MODEL_BONES_HPP
18385 #define EPIWORLD_MODEL_BONES_HPP
18386 
18387 template<typename TSeq>
18388 class Agent;
18389 
18390 template<typename TSeq>
18391 class AgentsSample;
18392 
18393 template<typename TSeq>
18394 class Virus;
18395 
18396 template<typename TSeq>
18397 class Viruses;
18398 
18399 template<typename TSeq>
18400 class Viruses_const;
18401 
18402 template<typename TSeq>
18403 class Tool;
18404 
18405 class AdjList;
18406 
18407 template<typename TSeq>
18408 class DataBase;
18409 
18410 template<typename TSeq>
18411 class Queue;
18412 
18413 template<typename TSeq>
18414 struct Event;
18415 
18416 template<typename TSeq>
18417 class GlobalEvent;
18418 
18419 template<typename TSeq>
18420 inline epiworld_double susceptibility_reduction_mixer_default(
18421  Agent<TSeq>* p,
18422  VirusPtr<TSeq> v,
18423  Model<TSeq>* m
18424  );
18425 template<typename TSeq>
18426 inline epiworld_double transmission_reduction_mixer_default(
18427  Agent<TSeq>* p,
18428  VirusPtr<TSeq> v,
18429  Model<TSeq>* m
18430  );
18431 template<typename TSeq>
18432 inline epiworld_double recovery_enhancer_mixer_default(
18433  Agent<TSeq>* p,
18434  VirusPtr<TSeq> v,
18435  Model<TSeq>* m
18436  );
18437 template<typename TSeq>
18438 inline epiworld_double death_reduction_mixer_default(
18439  Agent<TSeq>* p,
18440  VirusPtr<TSeq> v,
18441  Model<TSeq>* m
18442  );
18443 
18444 template<typename TSeq = EPI_DEFAULT_TSEQ>
18445 inline std::function<void(size_t,Model<TSeq>*)> make_save_run(
18446  std::string fmt = "%03lu-episimulation.csv",
18447  bool total_hist = true,
18448  bool virus_info = false,
18449  bool virus_hist = false,
18450  bool tool_info = false,
18451  bool tool_hist = false,
18452  bool transmission = false,
18453  bool transition = false,
18454  bool reproductive = false,
18455  bool generation = false
18456  );
18457 
18458 // template<typename TSeq>
18459 // class VirusPtr;
18460 
18461 // template<typename TSeq>
18462 // class ToolPtr;
18463 
18473 template<typename TSeq>
18474 class Model {
18475  friend class Agent<TSeq>;
18476  friend class AgentsSample<TSeq>;
18477  friend class DataBase<TSeq>;
18478  friend class Queue<TSeq>;
18479 protected:
18480 
18481  std::string name = ""; ///< Name of the model
18482 
18483  DataBase<TSeq> db = DataBase<TSeq>(*this);
18484 
18485  std::vector< Agent<TSeq> > population = {};
18486 
18487  bool using_backup = true;
18488  std::vector< Agent<TSeq> > population_backup = {};
18489 
18499  std::vector< Agent<TSeq> * > sampled_population;
18500  size_t sampled_population_n = 0u;
18501  std::vector< size_t > population_left;
18502  size_t population_left_n = 0u;
18504 
18514  double * agents_data = nullptr;
18515  size_t agents_data_ncols = 0u;
18517 
18518  bool directed = false;
18519 
18520  std::vector< VirusPtr<TSeq> > viruses = {};
18521  std::vector< ToolPtr<TSeq> > tools = {};
18522 
18523  std::vector< Entity<TSeq> > entities = {};
18524  std::vector< Entity<TSeq> > entities_backup = {};
18525 
18526  std::shared_ptr< std::mt19937 > engine = std::make_shared< std::mt19937 >();
18527 
18528  std::uniform_real_distribution<> runifd =
18529  std::uniform_real_distribution<> (0.0, 1.0);
18530  std::normal_distribution<> rnormd =
18531  std::normal_distribution<>(0.0);
18532  std::gamma_distribution<> rgammad =
18533  std::gamma_distribution<>();
18534  std::lognormal_distribution<> rlognormald =
18535  std::lognormal_distribution<>();
18536  std::exponential_distribution<> rexpd =
18537  std::exponential_distribution<>();
18538  std::binomial_distribution<> rbinomd =
18539  std::binomial_distribution<>();
18540  std::negative_binomial_distribution<> rnbinomd =
18541  std::negative_binomial_distribution<>();
18542  std::geometric_distribution<> rgeomd =
18543  std::geometric_distribution<>();
18544  std::poisson_distribution<> rpoissd =
18545  std::poisson_distribution<>();
18546 
18547  std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> rewire_fun;
18548  epiworld_double rewire_prop = 0.0;
18549 
18550  std::map<std::string, epiworld_double > parameters;
18551  epiworld_fast_uint ndays = 0;
18552  Progress pb;
18553 
18554  std::vector< UpdateFun<TSeq> > state_fun = {}; ///< Functions to update states
18555  std::vector< std::string > states_labels = {}; ///< Labels of the states
18556 
18558  std::function<void(Model<TSeq>*)> initial_states_fun = [](Model<TSeq> * /**/)
18559  -> void {};
18560 
18561  epiworld_fast_uint nstates = 0u;
18562 
18563  bool verbose = true;
18564  int current_date = 0;
18565 
18566  void dist_tools();
18567  void dist_virus();
18568  void dist_entities();
18569 
18570  std::chrono::time_point<std::chrono::steady_clock> time_start;
18571  std::chrono::time_point<std::chrono::steady_clock> time_end;
18572 
18573  // std::chrono::milliseconds
18574  std::chrono::duration<epiworld_double,std::micro> time_elapsed =
18575  std::chrono::duration<epiworld_double,std::micro>::zero();
18576  epiworld_fast_uint n_replicates = 0u;
18577  void chrono_start();
18578  void chrono_end();
18579 
18580  std::vector<GlobalEvent<TSeq>> globalevents;
18581 
18582  Queue<TSeq> queue;
18583  bool use_queuing = true;
18584 
18589  std::vector< Event<TSeq> > events = {};
18590  epiworld_fast_uint nactions = 0u;
18591 
18605  void events_add(
18606  Agent<TSeq> * agent_,
18607  VirusPtr<TSeq> virus_,
18608  ToolPtr<TSeq> tool_,
18609  Entity<TSeq> * entity_,
18610  epiworld_fast_int new_state_,
18611  epiworld_fast_int queue_,
18612  EventFun<TSeq> call_,
18613  int idx_agent_,
18614  int idx_object_
18615  );
18616 
18626  MixerFun<TSeq> susceptibility_reduction_mixer = susceptibility_reduction_mixer_default<TSeq>;
18627  MixerFun<TSeq> transmission_reduction_mixer = transmission_reduction_mixer_default<TSeq>;
18628  MixerFun<TSeq> recovery_enhancer_mixer = recovery_enhancer_mixer_default<TSeq>;
18629  MixerFun<TSeq> death_reduction_mixer = death_reduction_mixer_default<TSeq>;
18630 
18636  virtual Model<TSeq> * clone_ptr();
18637 
18638 public:
18639 
18640 
18641  std::vector<epiworld_double> array_double_tmp;
18642  std::vector<Virus<TSeq> * > array_virus_tmp;
18643 
18644  Model();
18645  Model(const Model<TSeq> & m);
18646  Model(Model<TSeq> & m);
18647  Model(Model<TSeq> && m);
18648  Model<TSeq> & operator=(const Model<TSeq> & m);
18649 
18650  virtual ~Model() {};
18651 
18660  void set_backup();
18661  // void restore_backup();
18663 
18664  DataBase<TSeq> & get_db();
18665  const DataBase<TSeq> & get_db() const;
18666  epiworld_double & operator()(std::string pname);
18667 
18668  size_t size() const;
18669 
18677  void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
18678  std::shared_ptr< std::mt19937 > & get_rand_endgine();
18679  void seed(size_t s);
18680  void set_rand_norm(epiworld_double mean, epiworld_double sd);
18681  void set_rand_unif(epiworld_double a, epiworld_double b);
18682  void set_rand_exp(epiworld_double lambda);
18683  void set_rand_gamma(epiworld_double alpha, epiworld_double beta);
18684  void set_rand_lognormal(epiworld_double mean, epiworld_double shape);
18685  void set_rand_binom(int n, epiworld_double p);
18686  void set_rand_nbinom(int n, epiworld_double p);
18687  void set_rand_geom(epiworld_double p);
18688  void set_rand_poiss(epiworld_double lambda);
18689  epiworld_double runif();
18690  epiworld_double runif(epiworld_double a, epiworld_double b);
18691  epiworld_double rnorm();
18692  epiworld_double rnorm(epiworld_double mean, epiworld_double sd);
18693  epiworld_double rgamma();
18694  epiworld_double rgamma(epiworld_double alpha, epiworld_double beta);
18695  epiworld_double rexp();
18696  epiworld_double rexp(epiworld_double lambda);
18697  epiworld_double rlognormal();
18698  epiworld_double rlognormal(epiworld_double mean, epiworld_double shape);
18699  int rbinom();
18700  int rbinom(int n, epiworld_double p);
18701  int rnbinom();
18702  int rnbinom(int n, epiworld_double p);
18703  int rgeom();
18704  int rgeom(epiworld_double p);
18705  int rpoiss();
18706  int rpoiss(epiworld_double lambda);
18708 
18721  void add_virus(Virus<TSeq> & v);
18722  void add_tool(Tool<TSeq> & t);
18723  void add_entity(Entity<TSeq> e);
18724  void rm_virus(size_t virus_pos);
18725  void rm_tool(size_t tool_pos);
18726  void rm_entity(size_t entity_id);
18728 
18739  void load_agents_entities_ties(std::string fn, int skip);
18740 
18744  void load_agents_entities_ties(
18745  const std::vector<int> & agents_ids,
18746  const std::vector<int> & entities_ids
18747  );
18748 
18749  void load_agents_entities_ties(
18750  const int * agents_id,
18751  const int * entities_id,
18752  size_t n
18753  );
18754 
18765  void agents_from_adjlist(
18766  std::string fn,
18767  int size,
18768  int skip = 0,
18769  bool directed = false
18770  );
18771 
18772  void agents_from_edgelist(
18773  const std::vector< int > & source,
18774  const std::vector< int > & target,
18775  int size,
18776  bool directed
18777  );
18778 
18779  void agents_from_adjlist(AdjList al);
18780 
18781  bool is_directed() const;
18782 
18783  std::vector< Agent<TSeq> > & get_agents();
18784 
18785  Agent<TSeq> & get_agent(size_t i);
18786 
18787  std::vector< epiworld_fast_uint > get_agents_states() const;
18788 
18789  std::vector< Viruses_const<TSeq> > get_agents_viruses() const;
18790 
18791  std::vector< Viruses<TSeq> > get_agents_viruses();
18792 
18793  std::vector< Entity<TSeq> > & get_entities();
18794 
18795  Entity<TSeq> & get_entity(size_t entity_id, int * entity_pos = nullptr);
18796 
18797  Model<TSeq> & agents_smallworld(
18798  epiworld_fast_uint n = 1000,
18799  epiworld_fast_uint k = 5,
18800  bool d = false,
18801  epiworld_double p = .01
18802  );
18803  void agents_empty_graph(epiworld_fast_uint n = 1000);
18805 
18816  void update_state();
18817  void mutate_virus();
18818  void next();
18819  virtual Model<TSeq> & run(
18820  epiworld_fast_uint ndays,
18821  int seed = -1
18822  );
18823  void run_multiple(
18824  epiworld_fast_uint ndays,
18825  epiworld_fast_uint nexperiments,
18826  int seed_ = -1,
18827  std::function<void(size_t,Model<TSeq>*)> fun = make_save_run<TSeq>(),
18828  bool reset = true,
18829  bool verbose = true,
18830  int nthreads = 1
18831  );
18833 
18834  size_t get_n_viruses() const;
18835  size_t get_n_tools() const;
18836  epiworld_fast_uint get_ndays() const;
18837  epiworld_fast_uint get_n_replicates() const;
18838  size_t get_n_entities() const;
18839  void set_ndays(epiworld_fast_uint ndays);
18840  bool get_verbose() const;
18841  Model<TSeq> & verbose_off();
18842  Model<TSeq> & verbose_on();
18843  int today() const;
18844 
18857  void set_rewire_fun(std::function<void(std::vector<Agent<TSeq>>*,Model<TSeq>*,epiworld_double)> fun);
18858  void set_rewire_prop(epiworld_double prop);
18859  epiworld_double get_rewire_prop() const;
18860  void rewire();
18862 
18875  void write_data(
18876  std::string fn_virus_info,
18877  std::string fn_virus_hist,
18878  std::string fn_tool_info,
18879  std::string fn_tool_hist,
18880  std::string fn_total_hist,
18881  std::string fn_transmission,
18882  std::string fn_transition,
18883  std::string fn_reproductive_number,
18884  std::string fn_generation_time
18885  ) const;
18886 
18898  void write_edgelist(
18899  std::string fn
18900  ) const;
18901 
18902  void write_edgelist(
18903  std::vector< int > & source,
18904  std::vector< int > & target
18905  ) const;
18907 
18908  std::map<std::string, epiworld_double> & params();
18909 
18921  virtual void reset();
18922  const Model<TSeq> & print(bool lite = false) const;
18923 
18939  void add_state(std::string lab, UpdateFun<TSeq> fun = nullptr);
18940  const std::vector< std::string > & get_states() const;
18941  size_t get_n_states() const;
18942  const std::vector< UpdateFun<TSeq> > & get_state_fun() const;
18943  void print_state_codes() const;
18945 
18954  virtual Model<TSeq> & initial_states(
18955  std::vector< double > /*proportions_*/,
18956  std::vector< int > /*queue_*/
18957  ) {return *this;};
18958 
18994  epiworld_double add_param(
18995  epiworld_double initial_val, std::string pname, bool overwrite = false
18996  );
18997  Model<TSeq> & read_params(std::string fn, bool overwrite = false);
18998  epiworld_double get_param(epiworld_fast_uint k);
18999  epiworld_double get_param(std::string pname);
19000  // void set_param(size_t k, epiworld_double val);
19001  void set_param(std::string pname, epiworld_double val);
19002  // epiworld_double par(epiworld_fast_uint k);
19003  epiworld_double par(std::string pname) const;
19005 
19006  void get_elapsed(
19007  std::string unit = "auto",
19008  epiworld_double * last_elapsed = nullptr,
19009  epiworld_double * total_elapsed = nullptr,
19010  std::string * unit_abbr = nullptr,
19011  bool print = true
19012  ) const;
19013 
19020  void set_user_data(std::vector< std::string > names);
19021  void add_user_data(epiworld_fast_uint j, epiworld_double x);
19022  void add_user_data(std::vector< epiworld_double > x);
19023  UserData<TSeq> & get_user_data();
19025 
19037  void add_globalevent(
19038  std::function<void(Model<TSeq>*)> fun,
19039  std::string name = "A global action",
19040  int date = -99
19041  );
19042 
19043  void add_globalevent(
19044  GlobalEvent<TSeq> action
19045  );
19046 
19047  GlobalEvent<TSeq> & get_globalevent(std::string name);
19048  GlobalEvent<TSeq> & get_globalevent(size_t i);
19049 
19050  void rm_globalevent(std::string name);
19051  void rm_globalevent(size_t i);
19052 
19053  void run_globalevents();
19054 
19055  void clear_state_set();
19056 
19065  void queuing_on();
19066  Model<TSeq> & queuing_off();
19067  bool is_queuing_on() const;
19068  Queue<TSeq> & get_queue();
19070 
19078  void set_susceptibility_reduction_mixer(MixerFun<TSeq> fun);
19079  void set_transmission_reduction_mixer(MixerFun<TSeq> fun);
19080  void set_recovery_enhancer_mixer(MixerFun<TSeq> fun);
19081  void set_death_reduction_mixer(MixerFun<TSeq> fun);
19083 
19084  const std::vector< VirusPtr<TSeq> > & get_viruses() const;
19085  const std::vector< ToolPtr<TSeq> > & get_tools() const;
19086  Virus<TSeq> & get_virus(size_t id);
19087  Tool<TSeq> & get_tool(size_t id);
19088 
19100  void set_agents_data(double * data_, size_t ncols_);
19101  double * get_agents_data();
19102  size_t get_agents_data_ncols() const;
19103 
19109  void set_name(std::string name);
19110  std::string get_name() const;
19111 
19112  bool operator==(const Model<TSeq> & other) const;
19113  bool operator!=(const Model<TSeq> & other) const {return !operator==(other);};
19114 
19120  void events_run();
19121 
19129  void draw(
19130  DiagramType diagram_type = DiagramType::Mermaid,
19131  const std::string & fn_output = "",
19132  bool self = false
19133  );
19134 
19135 
19136 };
19137 
19138 #endif
19139 /*//////////////////////////////////////////////////////////////////////////////
19141 
19142  End of -include/epiworld/model-bones.hpp-
19143 
19146 
19147 
19148 /*//////////////////////////////////////////////////////////////////////////////
19150 
19151  Start of -include/epiworld/agent-meat-virus-sampling.hpp-
19152 
19155 
19156 
19157 #ifndef EPIWORLD_AGENT_MEAT_VIRUS_SAMPLING
19158 #define EPIWORLD_AGENT_MEAT_VIRUS_SAMPLING
19159 
19164 namespace sampler {
19165 
19179 template<typename TSeq = EPI_DEFAULT_TSEQ>
19180 inline std::function<void(Agent<TSeq>*,Model<TSeq>*)> make_update_susceptible(
19181  std::vector< epiworld_fast_uint > exclude = {}
19182  )
19183 {
19184 
19185 
19186  if (exclude.size() == 0u)
19187  {
19188 
19189  std::function<void(Agent<TSeq>*,Model<TSeq>*)> sampler =
19190  [](Agent<TSeq> * p, Model<TSeq> * m) -> void
19191  {
19192 
19193  if (p->get_virus() != nullptr)
19194  throw std::logic_error(
19195  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
19196  std::string("Agent id ") + std::to_string(p->get_id()) +
19197  std::string(" has a virus.")
19198  );
19199 
19200  // This computes the prob of getting any neighbor variant
19201  size_t nviruses_tmp = 0u;
19202  for (auto & neighbor: p->get_neighbors())
19203  {
19204 
19205  auto & v = neighbor->get_virus();
19206  if (v == nullptr)
19207  continue;
19208 
19209  /* And it is a function of susceptibility_reduction as well */
19210  m->array_double_tmp[nviruses_tmp] =
19211  (1.0 - p->get_susceptibility_reduction(v, m)) *
19212  v->get_prob_infecting(m) *
19213  (1.0 - neighbor->get_transmission_reduction(v, m))
19214  ;
19215 
19216  m->array_virus_tmp[nviruses_tmp++] = &(*v);
19217 
19218  }
19219 
19220  // No virus to compute
19221  if (nviruses_tmp == 0u)
19222  return;
19223 
19224  // Running the roulette
19225  int which = roulette(nviruses_tmp, m);
19226 
19227  if (which < 0)
19228  return;
19229 
19230  p->set_virus(*m->array_virus_tmp[which], m);
19231 
19232  return;
19233  };
19234 
19235  return sampler;
19236 
19237  } else {
19238 
19239  // Making room for the query
19240  std::shared_ptr<std::vector<bool>> exclude_agent_bool =
19241  std::make_shared<std::vector<bool>>(0);
19242 
19243  std::shared_ptr<std::vector<epiworld_fast_uint>> exclude_agent_bool_idx =
19244  std::make_shared<std::vector<epiworld_fast_uint>>(exclude);
19245 
19246  std::function<void(Agent<TSeq>*,Model<TSeq>*)> sampler =
19247  [exclude_agent_bool,exclude_agent_bool_idx](Agent<TSeq> * p, Model<TSeq> * m) -> void
19248  {
19249 
19250  // The first time we call it, we need to initialize the vector
19251  if (exclude_agent_bool->size() == 0u)
19252  {
19253 
19254  exclude_agent_bool->resize(m->get_states().size(), false);
19255  for (auto s : *exclude_agent_bool_idx)
19256  {
19257  if (s >= exclude_agent_bool->size())
19258  throw std::logic_error(
19259  std::string("You are trying to exclude a state that is out of range: ") +
19260  std::to_string(s) + std::string(". There are only ") +
19261  std::to_string(exclude_agent_bool->size()) +
19262  std::string(" states in the model.")
19263  );
19264 
19265  exclude_agent_bool->operator[](s) = true;
19266 
19267  }
19268 
19269  }
19270 
19271  if (p->get_virus() != nullptr)
19272  throw std::logic_error(
19273  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
19274  std::string("Agent id ") + std::to_string(p->get_id()) +
19275  std::string(" has a virus.")
19276  );
19277 
19278  // This computes the prob of getting any neighbor variant
19279  size_t nviruses_tmp = 0u;
19280  for (auto & neighbor: p->get_neighbors())
19281  {
19282 
19283  // If the state is in the list, exclude it
19284  if (exclude_agent_bool->operator[](neighbor->get_state()))
19285  continue;
19286 
19287  auto & v = neighbor->get_virus();
19288  if (v == nullptr)
19289  continue;
19290 
19291 
19292  /* And it is a function of susceptibility_reduction as well */
19293  m->array_double_tmp[nviruses_tmp] =
19294  (1.0 - p->get_susceptibility_reduction(v, m)) *
19295  v->get_prob_infecting(m) *
19296  (1.0 - neighbor->get_transmission_reduction(v, m))
19297  ;
19298 
19299  m->array_virus_tmp[nviruses_tmp++] = &(*v);
19300 
19301  }
19302 
19303  // No virus to compute
19304  if (nviruses_tmp == 0u)
19305  return;
19306 
19307  // Running the roulette
19308  int which = roulette(nviruses_tmp, m);
19309 
19310  if (which < 0)
19311  return;
19312 
19313  p->set_virus(*m->array_virus_tmp[which], m);
19314 
19315  return;
19316 
19317  };
19318 
19319  return sampler;
19320 
19321  }
19322 
19323 }
19324 
19338 template<typename TSeq = EPI_DEFAULT_TSEQ>
19339 inline std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> make_sample_virus_neighbors(
19340  std::vector< epiworld_fast_uint > exclude = {}
19341 )
19342 {
19343  if (exclude.size() == 0u)
19344  {
19345 
19346  std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> res =
19347  [](Agent<TSeq> * p, Model<TSeq> * m) -> Virus<TSeq>* {
19348 
19349  if (p->get_virus() != nullptr)
19350  throw std::logic_error(
19351  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
19352  std::string("Agent id ") + std::to_string(p->get_id()) +
19353  std::string(" has a virus.")
19354  );
19355 
19356  // This computes the prob of getting any neighbor variant
19357  size_t nviruses_tmp = 0u;
19358  for (auto & neighbor: p->get_neighbors())
19359  {
19360 
19361  if (neighbor->get_virus() == nullptr)
19362  continue;
19363 
19364  auto & v = neighbor->get_virus();
19365 
19366  #ifdef EPI_DEBUG
19367  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
19368  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
19369  #endif
19370 
19371  /* And it is a function of susceptibility_reduction as well */
19372  m->array_double_tmp[nviruses_tmp] =
19373  (1.0 - p->get_susceptibility_reduction(v, m)) *
19374  v->get_prob_infecting(m) *
19375  (1.0 - neighbor->get_transmission_reduction(v, m))
19376  ;
19377 
19378  m->array_virus_tmp[nviruses_tmp++] = &(*v);
19379 
19380  }
19381 
19382  // No virus to compute
19383  if (nviruses_tmp == 0u)
19384  return nullptr;
19385 
19386  // Running the roulette
19387  int which = roulette(nviruses_tmp, m);
19388 
19389  if (which < 0)
19390  return nullptr;
19391 
19392  return m->array_virus_tmp[which];
19393 
19394  };
19395 
19396  return res;
19397 
19398 
19399  } else {
19400 
19401  // Making room for the query
19402  std::shared_ptr<std::vector<bool>> exclude_agent_bool =
19403  std::make_shared<std::vector<bool>>(0);
19404 
19405  std::shared_ptr<std::vector<epiworld_fast_uint>> exclude_agent_bool_idx =
19406  std::make_shared<std::vector<epiworld_fast_uint>>(exclude);
19407 
19408 
19409  std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> res =
19410  [exclude_agent_bool,exclude_agent_bool_idx](Agent<TSeq> * p, Model<TSeq> * m) -> Virus<TSeq>* {
19411 
19412  // The first time we call it, we need to initialize the vector
19413  if (exclude_agent_bool->size() == 0u)
19414  {
19415 
19416  exclude_agent_bool->resize(m->get_states().size(), false);
19417  for (auto s : *exclude_agent_bool_idx)
19418  {
19419  if (s >= exclude_agent_bool->size())
19420  throw std::logic_error(
19421  std::string("You are trying to exclude a state that is out of range: ") +
19422  std::to_string(s) + std::string(". There are only ") +
19423  std::to_string(exclude_agent_bool->size()) +
19424  std::string(" states in the model.")
19425  );
19426 
19427  exclude_agent_bool->operator[](s) = true;
19428 
19429  }
19430 
19431  }
19432 
19433  if (p->get_virus() != nullptr)
19434  throw std::logic_error(
19435  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense! ") +
19436  std::string("Agent id ") + std::to_string(p->get_id()) +
19437  std::string(" has a virus.")
19438  );
19439 
19440  // This computes the prob of getting any neighbor variant
19441  size_t nviruses_tmp = 0u;
19442  for (auto & neighbor: p->get_neighbors())
19443  {
19444 
19445  // If the state is in the list, exclude it
19446  if (exclude_agent_bool->operator[](neighbor->get_state()))
19447  continue;
19448 
19449  if (neighbor->get_virus() == nullptr)
19450  continue;
19451 
19452  auto & v = neighbor->get_virus();
19453 
19454  #ifdef EPI_DEBUG
19455  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
19456  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
19457  #endif
19458 
19459  /* And it is a function of susceptibility_reduction as well */
19460  m->array_double_tmp[nviruses_tmp] =
19461  (1.0 - p->get_susceptibility_reduction(v, m)) *
19462  v->get_prob_infecting(m) *
19463  (1.0 - neighbor->get_transmission_reduction(v, m))
19464  ;
19465 
19466  m->array_virus_tmp[nviruses_tmp++] = &(*v);
19467 
19468  }
19469 
19470  // No virus to compute
19471  if (nviruses_tmp == 0u)
19472  return nullptr;
19473 
19474  // Running the roulette
19475  int which = roulette(nviruses_tmp, m);
19476 
19477  if (which < 0)
19478  return nullptr;
19479 
19480  return m->array_virus_tmp[which];
19481 
19482  };
19483 
19484  return res;
19485 
19486  }
19487 
19488 }
19489 
19506 template<typename TSeq = EPI_DEFAULT_TSEQ>
19508 {
19509 
19510  if (p->get_virus() != nullptr)
19511  throw std::logic_error(
19512  std::string("Using the -default_update_susceptible- on agents WITH viruses makes no sense!") +
19513  std::string("Agent id ") + std::to_string(p->get_id()) +
19514  std::string(" has a virus.")
19515  );
19516 
19517  // This computes the prob of getting any neighbor variant
19518  size_t nviruses_tmp = 0u;
19519  for (auto & neighbor: p->get_neighbors())
19520  {
19521  #ifdef EPI_DEBUG
19522  int _vcount_neigh = 0;
19523  #endif
19524 
19525  if (neighbor->get_virus() == nullptr)
19526  continue;
19527 
19528  auto & v = neighbor->get_virus();
19529 
19530  #ifdef EPI_DEBUG
19531  if (nviruses_tmp >= m->array_virus_tmp.size())
19532  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
19533  #endif
19534 
19535  /* And it is a function of susceptibility_reduction as well */
19536  m->array_double_tmp[nviruses_tmp] =
19537  (1.0 - p->get_susceptibility_reduction(v, m)) *
19538  v->get_prob_infecting(m) *
19539  (1.0 - neighbor->get_transmission_reduction(v, m))
19540  ;
19541 
19542  m->array_virus_tmp[nviruses_tmp++] = &(*v);
19543 
19544  #ifdef EPI_DEBUG
19545  if (
19546  (m->array_double_tmp[nviruses_tmp - 1] < 0.0) |
19547  (m->array_double_tmp[nviruses_tmp - 1] > 1.0)
19548  )
19549  {
19550  printf_epiworld(
19551  "[epi-debug] Agent %i's virus %i has transmission prob outside of [0, 1]: %.4f!\n",
19552  static_cast<int>(neighbor->get_id()),
19553  static_cast<int>(_vcount_neigh++),
19554  m->array_double_tmp[nviruses_tmp - 1]
19555  );
19556  }
19557  #endif
19558 
19559  }
19560 
19561 
19562  // No virus to compute
19563  if (nviruses_tmp == 0u)
19564  return nullptr;
19565 
19566  #ifdef EPI_DEBUG
19567  m->get_db().n_transmissions_potential++;
19568  #endif
19569 
19570  // Running the roulette
19571  int which = roulette(nviruses_tmp, m);
19572 
19573  if (which < 0)
19574  return nullptr;
19575 
19576  #ifdef EPI_DEBUG
19577  m->get_db().n_transmissions_today++;
19578  #endif
19579 
19580  return m->array_virus_tmp[which];
19581 
19582 }
19583 
19584 }
19585 
19586 #endif
19587 /*//////////////////////////////////////////////////////////////////////////////
19589 
19590  End of -include/epiworld/agent-meat-virus-sampling.hpp-
19591 
19594 
19595 
19596 /*//////////////////////////////////////////////////////////////////////////////
19598 
19599  Start of -include/epiworld/config.hpp-
19600 
19603 
19604 
19605 #ifndef EPIWORLD_CONFIG_HPP
19606 #define EPIWORLD_CONFIG_HPP
19607 
19608 #ifndef printf_epiworld
19609  #define printf_epiworld fflush(stdout);printf
19610 #endif
19611 
19612 // In case the user has a way to stop the program
19613 // This is called during `run_multiple()` and it is
19614 // passed the simulation number.
19615 #ifndef EPI_CHECK_USER_INTERRUPT
19616  #define EPI_CHECK_USER_INTERRUPT(a)
19617 #endif
19618 
19619 #ifndef EPIWORLD_MAXNEIGHBORS
19620  #define EPIWORLD_MAXNEIGHBORS 1048576
19621 #endif
19622 
19623 #if defined(_OPENMP) || defined(__OPENMP)
19624  #include <omp.h>
19625 // #else
19626 // #define omp_get_thread_num() 0
19627 // #define omp_set_num_threads() 1
19628 #endif
19629 
19630 #ifndef epiworld_double
19631  #define epiworld_double float
19632 #endif
19633 
19634 #ifndef epiworld_fast_int
19635  #define epiworld_fast_int int
19636 #endif
19637 
19638 #ifndef epiworld_fast_uint
19639  #define epiworld_fast_uint unsigned long long int
19640 #endif
19641 
19642 #define EPI_DEFAULT_TSEQ int
19643 
19644 #ifndef EPI_MAX_TRACKING
19645  #define EPI_MAX_TRACKING 200
19646 #endif
19647 
19648 template<typename TSeq = EPI_DEFAULT_TSEQ>
19649 class Model;
19650 
19651 template<typename TSeq = EPI_DEFAULT_TSEQ>
19652 class Agent;
19653 
19654 template<typename TSeq = EPI_DEFAULT_TSEQ>
19655 class PersonTools;
19656 
19657 template<typename TSeq = EPI_DEFAULT_TSEQ>
19658 class Virus;
19659 
19660 template<typename TSeq = EPI_DEFAULT_TSEQ>
19661 class Viruses;
19662 
19663 template<typename TSeq = EPI_DEFAULT_TSEQ>
19664 class Viruses_const;
19665 
19666 template<typename TSeq = EPI_DEFAULT_TSEQ>
19667 class Tool;
19668 
19669 template<typename TSeq = EPI_DEFAULT_TSEQ>
19670 class Tools;
19671 
19672 template<typename TSeq = EPI_DEFAULT_TSEQ>
19673 class Tools_const;
19674 
19675 template<typename TSeq = EPI_DEFAULT_TSEQ>
19676 class Entity;
19677 
19678 template<typename TSeq = EPI_DEFAULT_TSEQ>
19679 using VirusPtr = std::shared_ptr< Virus< TSeq > >;
19680 
19681 template<typename TSeq = EPI_DEFAULT_TSEQ>
19682 using ToolPtr = std::shared_ptr< Tool< TSeq > >;
19683 
19684 template<typename TSeq = EPI_DEFAULT_TSEQ>
19685 using ToolFun = std::function<epiworld_double(Tool<TSeq>&,Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
19686 
19687 template<typename TSeq = EPI_DEFAULT_TSEQ>
19688 using MixerFun = std::function<epiworld_double(Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
19689 
19690 template<typename TSeq = EPI_DEFAULT_TSEQ>
19691 using MutFun = std::function<bool(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
19692 
19693 template<typename TSeq = EPI_DEFAULT_TSEQ>
19694 using PostRecoveryFun = std::function<void(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
19695 
19696 template<typename TSeq = EPI_DEFAULT_TSEQ>
19697 using VirusFun = std::function<epiworld_double(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
19698 
19699 template<typename TSeq = EPI_DEFAULT_TSEQ>
19700 using UpdateFun = std::function<void(Agent<TSeq>*,Model<TSeq>*)>;
19701 
19702 template<typename TSeq = EPI_DEFAULT_TSEQ>
19703 using GlobalFun = std::function<void(Model<TSeq>*)>;
19704 
19705 template<typename TSeq>
19706 struct Event;
19707 
19708 template<typename TSeq = EPI_DEFAULT_TSEQ>
19709 using EventFun = std::function<void(Event<TSeq>&,Model<TSeq>*)>;
19710 
19714 template<typename TSeq = EPI_DEFAULT_TSEQ>
19715 using VirusToAgentFun = std::function<void(Virus<TSeq>&,Model<TSeq>*)>;
19716 
19720 template<typename TSeq = EPI_DEFAULT_TSEQ>
19721 using ToolToAgentFun = std::function<void(Tool<TSeq>&,Model<TSeq>*)>;
19722 
19726 template<typename TSeq = EPI_DEFAULT_TSEQ>
19727 using EntityToAgentFun = std::function<void(Entity<TSeq>&,Model<TSeq>*)>;
19728 
19734 template<typename TSeq = EPI_DEFAULT_TSEQ>
19735 struct Event {
19736  Agent<TSeq> * agent;
19737  VirusPtr<TSeq> virus;
19738  ToolPtr<TSeq> tool;
19739  Entity<TSeq> * entity;
19740  epiworld_fast_int new_state;
19741  epiworld_fast_int queue;
19742  EventFun<TSeq> call;
19743  int idx_agent;
19744  int idx_object;
19745 public:
19762  Event(
19763  Agent<TSeq> * agent_,
19764  VirusPtr<TSeq> & virus_,
19765  ToolPtr<TSeq> & tool_,
19766  Entity<TSeq> * entity_,
19767  epiworld_fast_int new_state_,
19768  epiworld_fast_int queue_,
19769  EventFun<TSeq> & call_,
19770  int idx_agent_,
19771  int idx_object_
19772  ) : agent(agent_), virus(virus_), tool(tool_), entity(entity_),
19773  new_state(new_state_),
19774  queue(queue_), call(call_), idx_agent(idx_agent_), idx_object(idx_object_) {
19775  return;
19776  };
19777 };
19778 
19786 #ifndef DEFAULT_TOOL_CONTAGION_REDUCTION
19787  #define DEFAULT_TOOL_CONTAGION_REDUCTION 0.0
19788 #endif
19789 
19790 #ifndef DEFAULT_TOOL_TRANSMISSION_REDUCTION
19791  #define DEFAULT_TOOL_TRANSMISSION_REDUCTION 0.0
19792 #endif
19793 
19794 #ifndef DEFAULT_TOOL_RECOVERY_ENHANCER
19795  #define DEFAULT_TOOL_RECOVERY_ENHANCER 0.0
19796 #endif
19797 
19798 #ifndef DEFAULT_TOOL_DEATH_REDUCTION
19799  #define DEFAULT_TOOL_DEATH_REDUCTION 0.0
19800 #endif
19801 
19802 #ifndef EPI_DEFAULT_VIRUS_PROB_INFECTION
19803  #define EPI_DEFAULT_VIRUS_PROB_INFECTION 1.0
19804 #endif
19805 
19806 #ifndef EPI_DEFAULT_VIRUS_PROB_RECOVERY
19807  #define EPI_DEFAULT_VIRUS_PROB_RECOVERY 0.1428
19808 #endif
19809 
19810 #ifndef EPI_DEFAULT_VIRUS_PROB_DEATH
19811  #define EPI_DEFAULT_VIRUS_PROB_DEATH 0.0
19812 #endif
19813 
19814 #ifndef EPI_DEFAULT_INCUBATION_DAYS
19815  #define EPI_DEFAULT_INCUBATION_DAYS 7.0
19816 #endif
19818 
19819 #ifdef EPI_DEBUG
19820  #define EPI_DEBUG_PRINTF printf_epiworld
19821 
19822  #define EPI_DEBUG_ERROR(etype, msg) \
19823  (etype)("[[epi-debug]] (error) " + std::string(msg));
19824 
19825  #define EPI_DEBUG_NOTIFY_ACTIVE() \
19826  EPI_DEBUG_PRINTF("DEBUGGING ON (compiled with EPI_DEBUG defined)%s\n", "");
19827 
19828  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect) \
19829  for (auto & v : vect) \
19830  if (static_cast<double>(v) < 0.0) \
19831  throw EPI_DEBUG_ERROR(std::logic_error, "A negative value not allowed.");
19832 
19833  #define EPI_DEBUG_SUM_DBL(vect, num) \
19834  double _epi_debug_sum = 0.0; \
19835  for (auto & v : vect) \
19836  { \
19837  _epi_debug_sum += static_cast<double>(v);\
19838  if (_epi_debug_sum > static_cast<double>(num)) \
19839  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
19840  }
19841 
19842  #define EPI_DEBUG_SUM_INT(vect, num) \
19843  int _epi_debug_sum = 0; \
19844  for (auto & v : vect) \
19845  { \
19846  _epi_debug_sum += static_cast<int>(v);\
19847  if (_epi_debug_sum > static_cast<int>(num)) \
19848  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
19849  }
19850 
19851  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c) \
19852  if (a.size() != b.size()) {\
19853  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
19854  EPI_DEBUG_PRINTF("Size of vector a: %lu\n", (a).size());\
19855  EPI_DEBUG_PRINTF("Size of vector b: %lu\n", (b).size());\
19856  throw EPI_DEBUG_ERROR(std::length_error, "The vectors do not match size."); \
19857  }\
19858  for (int _i = 0; _i < static_cast<int>(a.size()); ++_i) \
19859  if (a[_i] != b[_i]) {\
19860  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
19861  EPI_DEBUG_PRINTF("Iterating the last 5 values%s:\n", ""); \
19862  for (int _j = std::max(0, static_cast<int>(_i) - 4); _j <= _i; ++_j) \
19863  { \
19864  EPI_DEBUG_PRINTF( \
19865  "a[%i]: %i; b[%i]: %i\n", \
19866  _j, \
19867  static_cast<int>(a[_j]), \
19868  _j, static_cast<int>(b[_j])); \
19869  } \
19870  throw EPI_DEBUG_ERROR(std::logic_error, "The vectors do not match."); \
19871  }
19872 
19873  #define EPI_DEBUG_FAIL_AT_TRUE(a,b) \
19874  if (a) \
19875  {\
19876  throw EPI_DEBUG_ERROR(std::logic_error, b); \
19877  }
19878 
19879  #define epiexception(a) std::logic_error
19880 #else
19881  #define EPI_DEBUG_PRINTF(fmt, ...)
19882  #define EPI_DEBUG_ERROR(fmt, ...)
19883  #define EPI_DEBUG_NOTIFY_ACTIVE()
19884  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect)
19885  #define EPI_DEBUG_SUM_DBL(vect, num)
19886  #define EPI_DEBUG_SUM_INT(vect, num)
19887  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c)
19888  #define EPI_DEBUG_FAIL_AT_TRUE(a, b) \
19889  if (a) \
19890  return false;
19891  #define epiexception(a) a
19892 #endif
19893 
19894 #if defined(EPI_DEBUG_NO_THREAD_ID) || (!defined(__OPENMP) && !defined(_OPENMP))
19895  #define EPI_GET_THREAD_ID() 0
19896 #else
19897  #define EPI_GET_THREAD_ID() omp_get_thread_num()
19898 #endif
19899 
19900 #endif
19901 /*//////////////////////////////////////////////////////////////////////////////
19903 
19904  End of -include/epiworld/config.hpp-
19905 
19908 
19909 
19910 
19922 template<typename TSeq = EPI_DEFAULT_TSEQ>
19923 inline void default_update_susceptible(
19924  Agent<TSeq> * p,
19925  Model<TSeq> * m
19926  )
19927 {
19928 
19929  Virus<TSeq> * virus = sampler::sample_virus_single<TSeq>(p, m);
19930 
19931  if (virus == nullptr)
19932  return;
19933 
19934  p->set_virus(*virus, m);
19935 
19936  return;
19937 
19938 }
19939 
19940 template<typename TSeq = EPI_DEFAULT_TSEQ>
19941 inline void default_update_exposed(Agent<TSeq> * p, Model<TSeq> * m) {
19942 
19943  if (p->get_virus() == nullptr)
19944  throw std::logic_error(
19945  std::string("Using the -default_update_exposed- on agents WITHOUT viruses makes no sense! ") +
19946  std::string("Agent id ") + std::to_string(p->get_id()) + std::string(" has no virus registered.")
19947  );
19948 
19949  // Die
19950  auto & virus = p->get_virus();
19951  m->array_double_tmp[0u] =
19952  virus->get_prob_death(m) * (1.0 - p->get_death_reduction(virus, m));
19953 
19954  // Recover
19955  m->array_double_tmp[1u] =
19956  1.0 - (1.0 - virus->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(virus, m));
19957 
19958 
19959  // Running the roulette
19960  int which = roulette(2u, m);
19961 
19962  if (which < 0)
19963  return;
19964 
19965  // Which roulette happen?
19966  if (which == 0u) // If odd
19967  {
19968 
19969  p->rm_agent_by_virus(m);
19970 
19971  } else {
19972 
19973  p->rm_virus(m);
19974 
19975  }
19976 
19977  return ;
19978 
19979 };
19980 
19981 #endif
19982 /*//////////////////////////////////////////////////////////////////////////////
19984 
19985  End of -include/epiworld/agent-meat-state.hpp-
19986 
19989 
19990 
19991 /*//////////////////////////////////////////////////////////////////////////////
19993 
19994  Start of -include/epiworld/agent-bones.hpp-
19995 
19998 
19999 
20000 #ifndef EPIWORLD_PERSON_BONES_HPP
20001 #define EPIWORLD_PERSON_BONES_HPP
20002 
20003 template<typename TSeq>
20004 class Model;
20005 
20006 template<typename TSeq>
20007 class Virus;
20008 
20009 template<typename TSeq>
20010 class Viruses;
20011 
20012 template<typename TSeq>
20013 class Viruses_const;
20014 
20015 template<typename TSeq>
20016 class Tool;
20017 
20018 template<typename TSeq>
20019 class Tools;
20020 
20021 template<typename TSeq>
20022 class Tools_const;
20023 
20024 template<typename TSeq>
20025 class Queue;
20026 
20027 template<typename TSeq>
20028 struct Event;
20029 
20030 template<typename TSeq>
20031 class Entity;
20032 
20033 template<typename TSeq>
20034 class Entities;
20035 
20036 template<typename TSeq>
20037 inline void default_add_virus(Event<TSeq> & a, Model<TSeq> * m);
20038 
20039 template<typename TSeq>
20040 inline void default_add_tool(Event<TSeq> & a, Model<TSeq> * m);
20041 
20042 template<typename TSeq>
20043 inline void default_add_entity(Event<TSeq> & a, Model<TSeq> * m);
20044 
20045 template<typename TSeq>
20046 inline void default_rm_virus(Event<TSeq> & a, Model<TSeq> * m);
20047 
20048 template<typename TSeq>
20049 inline void default_rm_tool(Event<TSeq> & a, Model<TSeq> * m);
20050 
20051 template<typename TSeq>
20052 inline void default_rm_entity(Event<TSeq> & a, Model<TSeq> * m);
20053 
20054 template<typename TSeq>
20055 inline void default_change_state(Event<TSeq> & a, Model<TSeq> * m);
20056 
20057 
20058 
20064 template<typename TSeq>
20065 class Agent {
20066  friend class Model<TSeq>;
20067  friend class Virus<TSeq>;
20068  friend class Tool<TSeq>;
20069  friend class Tools<TSeq>;
20070  friend class Tools_const<TSeq>;
20071  friend class Queue<TSeq>;
20072  friend class Entities<TSeq>;
20073  friend class AgentsSample<TSeq>;
20074  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20075  friend void default_add_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20076  friend void default_add_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20077  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20078  friend void default_rm_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20079  friend void default_rm_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20080  friend void default_change_state<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
20081 private:
20082 
20083  Model<TSeq> * model;
20084 
20085  std::vector< size_t > * neighbors = nullptr;
20086  std::vector< size_t > * neighbors_locations = nullptr;
20087  size_t n_neighbors = 0u;
20088 
20089  std::vector< size_t > entities;
20090  std::vector< size_t > entities_locations;
20091  size_t n_entities = 0u;
20092 
20093  unsigned int state = 0u;
20094  unsigned int state_prev = 0u; ///< For accounting, if need to undo a change.
20095 
20096  int state_last_changed = -1; ///< Last time the agent was updated.
20097  int id = -1;
20098 
20099  VirusPtr<TSeq> virus = nullptr;
20100 
20101  std::vector< ToolPtr<TSeq> > tools;
20102  unsigned int n_tools = 0u;
20103 
20104 public:
20105 
20106  Agent();
20107  Agent(Agent<TSeq> && p);
20108  Agent(const Agent<TSeq> & p);
20109  Agent<TSeq> & operator=(const Agent<TSeq> & other_agent);
20110  ~Agent();
20111 
20123  void add_tool(
20124  ToolPtr<TSeq> & tool,
20125  Model<TSeq> * model,
20126  epiworld_fast_int state_new = -99,
20127  epiworld_fast_int queue = -99
20128  );
20129 
20130  void add_tool(
20131  const Tool<TSeq> & tool,
20132  Model<TSeq> * model,
20133  epiworld_fast_int state_new = -99,
20134  epiworld_fast_int queue = -99
20135  );
20136 
20137  void set_virus(
20138  VirusPtr<TSeq> & virus,
20139  Model<TSeq> * model,
20140  epiworld_fast_int state_new = -99,
20141  epiworld_fast_int queue = -99
20142  );
20143 
20144  void set_virus(
20145  const Virus<TSeq> & virus,
20146  Model<TSeq> * model,
20147  epiworld_fast_int state_new = -99,
20148  epiworld_fast_int queue = -99
20149  );
20150 
20151  void add_entity(
20152  Entity<TSeq> & entity,
20153  Model<TSeq> * model,
20154  epiworld_fast_int state_new = -99,
20155  epiworld_fast_int queue = -99
20156  );
20157 
20158  void rm_tool(
20159  epiworld_fast_uint tool_idx,
20160  Model<TSeq> * model,
20161  epiworld_fast_int state_new = -99,
20162  epiworld_fast_int queue = -99
20163  );
20164 
20165  void rm_tool(
20166  ToolPtr<TSeq> & tool,
20167  Model<TSeq> * model,
20168  epiworld_fast_int state_new = -99,
20169  epiworld_fast_int queue = -99
20170  );
20171 
20172  void rm_virus(
20173  Model<TSeq> * model,
20174  epiworld_fast_int state_new = -99,
20175  epiworld_fast_int queue = -99
20176  );
20177 
20178  void rm_entity(
20179  epiworld_fast_uint entity_idx,
20180  Model<TSeq> * model,
20181  epiworld_fast_int state_new = -99,
20182  epiworld_fast_int queue = -99
20183  );
20184 
20185  void rm_entity(
20186  Entity<TSeq> & entity,
20187  Model<TSeq> * model,
20188  epiworld_fast_int state_new = -99,
20189  epiworld_fast_int queue = -99
20190  );
20191 
20192  void rm_agent_by_virus(Model<TSeq> * model); ///< Agent removed by virus
20194 
20202  epiworld_double get_susceptibility_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
20203  epiworld_double get_transmission_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
20204  epiworld_double get_recovery_enhancer(VirusPtr<TSeq> v, Model<TSeq> * model);
20205  epiworld_double get_death_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
20207 
20208  int get_id() const; ///< Id of the individual
20209 
20210  VirusPtr<TSeq> & get_virus();
20211  const VirusPtr<TSeq> & get_virus() const;
20212 
20213  ToolPtr<TSeq> & get_tool(int i);
20214  Tools<TSeq> get_tools();
20215  const Tools_const<TSeq> get_tools() const;
20216  size_t get_n_tools() const noexcept;
20217 
20218  void mutate_virus();
20219  void add_neighbor(
20220  Agent<TSeq> & p,
20221  bool check_source = true,
20222  bool check_target = true
20223  );
20224 
20232  void swap_neighbors(
20233  Agent<TSeq> & other,
20234  size_t n_this,
20235  size_t n_other
20236  );
20237 
20238  std::vector< Agent<TSeq> * > get_neighbors();
20239  size_t get_n_neighbors() const;
20240 
20241  void change_state(
20242  Model<TSeq> * model,
20243  epiworld_fast_uint new_state,
20244  epiworld_fast_int queue = 0
20245  );
20246 
20247  const unsigned int & get_state() const;
20248 
20249  void reset();
20250 
20251  bool has_tool(epiworld_fast_uint t) const;
20252  bool has_tool(std::string name) const;
20253  bool has_tool(const Tool<TSeq> & t) const;
20254  bool has_virus(epiworld_fast_uint t) const;
20255  bool has_virus(std::string name) const;
20256  bool has_virus(const Virus<TSeq> & v) const;
20257  bool has_entity(epiworld_fast_uint t) const;
20258  bool has_entity(std::string name) const;
20259 
20260  void print(bool compressed = false) const;
20261 
20278  double & operator()(size_t j);
20279  double & operator[](size_t j);
20280  double operator()(size_t j) const;
20281  double operator[](size_t j) const;
20283 
20284  Entities<TSeq> get_entities();
20285  const Entities_const<TSeq> get_entities() const;
20286  const Entity<TSeq> & get_entity(size_t i) const;
20287  Entity<TSeq> & get_entity(size_t i);
20288  size_t get_n_entities() const;
20289 
20290  bool operator==(const Agent<TSeq> & other) const;
20291  bool operator!=(const Agent<TSeq> & other) const {return !operator==(other);};
20292 
20293 };
20294 
20295 
20296 
20297 #endif
20298 /*//////////////////////////////////////////////////////////////////////////////
20300 
20301  End of -include/epiworld/agent-bones.hpp-
20302 
20305 
20306 
20307 /*//////////////////////////////////////////////////////////////////////////////
20309 
20310  Start of -include/epiworld/agent-meat.hpp-
20311 
20314 
20315 
20316 #ifndef EPIWORLD_PERSON_MEAT_HPP
20317 #define EPIWORLD_PERSON_MEAT_HPP
20318 
20319 #include <vector>
20320 #include <string>
20321 /*//////////////////////////////////////////////////////////////////////////////
20323 
20324  Start of -include/epiworld/config.hpp-
20325 
20328 
20329 
20330 #ifndef EPIWORLD_CONFIG_HPP
20331 #define EPIWORLD_CONFIG_HPP
20332 
20333 #ifndef printf_epiworld
20334  #define printf_epiworld fflush(stdout);printf
20335 #endif
20336 
20337 // In case the user has a way to stop the program
20338 // This is called during `run_multiple()` and it is
20339 // passed the simulation number.
20340 #ifndef EPI_CHECK_USER_INTERRUPT
20341  #define EPI_CHECK_USER_INTERRUPT(a)
20342 #endif
20343 
20344 #ifndef EPIWORLD_MAXNEIGHBORS
20345  #define EPIWORLD_MAXNEIGHBORS 1048576
20346 #endif
20347 
20348 #if defined(_OPENMP) || defined(__OPENMP)
20349  #include <omp.h>
20350 // #else
20351 // #define omp_get_thread_num() 0
20352 // #define omp_set_num_threads() 1
20353 #endif
20354 
20355 #ifndef epiworld_double
20356  #define epiworld_double float
20357 #endif
20358 
20359 #ifndef epiworld_fast_int
20360  #define epiworld_fast_int int
20361 #endif
20362 
20363 #ifndef epiworld_fast_uint
20364  #define epiworld_fast_uint unsigned long long int
20365 #endif
20366 
20367 #define EPI_DEFAULT_TSEQ int
20368 
20369 #ifndef EPI_MAX_TRACKING
20370  #define EPI_MAX_TRACKING 200
20371 #endif
20372 
20373 template<typename TSeq = EPI_DEFAULT_TSEQ>
20374 class Model;
20375 
20376 template<typename TSeq = EPI_DEFAULT_TSEQ>
20377 class Agent;
20378 
20379 template<typename TSeq = EPI_DEFAULT_TSEQ>
20380 class PersonTools;
20381 
20382 template<typename TSeq = EPI_DEFAULT_TSEQ>
20383 class Virus;
20384 
20385 template<typename TSeq = EPI_DEFAULT_TSEQ>
20386 class Viruses;
20387 
20388 template<typename TSeq = EPI_DEFAULT_TSEQ>
20389 class Viruses_const;
20390 
20391 template<typename TSeq = EPI_DEFAULT_TSEQ>
20392 class Tool;
20393 
20394 template<typename TSeq = EPI_DEFAULT_TSEQ>
20395 class Tools;
20396 
20397 template<typename TSeq = EPI_DEFAULT_TSEQ>
20398 class Tools_const;
20399 
20400 template<typename TSeq = EPI_DEFAULT_TSEQ>
20401 class Entity;
20402 
20403 template<typename TSeq = EPI_DEFAULT_TSEQ>
20404 using VirusPtr = std::shared_ptr< Virus< TSeq > >;
20405 
20406 template<typename TSeq = EPI_DEFAULT_TSEQ>
20407 using ToolPtr = std::shared_ptr< Tool< TSeq > >;
20408 
20409 template<typename TSeq = EPI_DEFAULT_TSEQ>
20410 using ToolFun = std::function<epiworld_double(Tool<TSeq>&,Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
20411 
20412 template<typename TSeq = EPI_DEFAULT_TSEQ>
20413 using MixerFun = std::function<epiworld_double(Agent<TSeq>*,VirusPtr<TSeq>,Model<TSeq>*)>;
20414 
20415 template<typename TSeq = EPI_DEFAULT_TSEQ>
20416 using MutFun = std::function<bool(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
20417 
20418 template<typename TSeq = EPI_DEFAULT_TSEQ>
20419 using PostRecoveryFun = std::function<void(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
20420 
20421 template<typename TSeq = EPI_DEFAULT_TSEQ>
20422 using VirusFun = std::function<epiworld_double(Agent<TSeq>*,Virus<TSeq>&,Model<TSeq>*)>;
20423 
20424 template<typename TSeq = EPI_DEFAULT_TSEQ>
20425 using UpdateFun = std::function<void(Agent<TSeq>*,Model<TSeq>*)>;
20426 
20427 template<typename TSeq = EPI_DEFAULT_TSEQ>
20428 using GlobalFun = std::function<void(Model<TSeq>*)>;
20429 
20430 template<typename TSeq>
20431 struct Event;
20432 
20433 template<typename TSeq = EPI_DEFAULT_TSEQ>
20434 using EventFun = std::function<void(Event<TSeq>&,Model<TSeq>*)>;
20435 
20439 template<typename TSeq = EPI_DEFAULT_TSEQ>
20440 using VirusToAgentFun = std::function<void(Virus<TSeq>&,Model<TSeq>*)>;
20441 
20445 template<typename TSeq = EPI_DEFAULT_TSEQ>
20446 using ToolToAgentFun = std::function<void(Tool<TSeq>&,Model<TSeq>*)>;
20447 
20451 template<typename TSeq = EPI_DEFAULT_TSEQ>
20452 using EntityToAgentFun = std::function<void(Entity<TSeq>&,Model<TSeq>*)>;
20453 
20459 template<typename TSeq = EPI_DEFAULT_TSEQ>
20460 struct Event {
20461  Agent<TSeq> * agent;
20462  VirusPtr<TSeq> virus;
20463  ToolPtr<TSeq> tool;
20464  Entity<TSeq> * entity;
20465  epiworld_fast_int new_state;
20466  epiworld_fast_int queue;
20467  EventFun<TSeq> call;
20468  int idx_agent;
20469  int idx_object;
20470 public:
20487  Event(
20488  Agent<TSeq> * agent_,
20489  VirusPtr<TSeq> & virus_,
20490  ToolPtr<TSeq> & tool_,
20491  Entity<TSeq> * entity_,
20492  epiworld_fast_int new_state_,
20493  epiworld_fast_int queue_,
20494  EventFun<TSeq> & call_,
20495  int idx_agent_,
20496  int idx_object_
20497  ) : agent(agent_), virus(virus_), tool(tool_), entity(entity_),
20498  new_state(new_state_),
20499  queue(queue_), call(call_), idx_agent(idx_agent_), idx_object(idx_object_) {
20500  return;
20501  };
20502 };
20503 
20511 #ifndef DEFAULT_TOOL_CONTAGION_REDUCTION
20512  #define DEFAULT_TOOL_CONTAGION_REDUCTION 0.0
20513 #endif
20514 
20515 #ifndef DEFAULT_TOOL_TRANSMISSION_REDUCTION
20516  #define DEFAULT_TOOL_TRANSMISSION_REDUCTION 0.0
20517 #endif
20518 
20519 #ifndef DEFAULT_TOOL_RECOVERY_ENHANCER
20520  #define DEFAULT_TOOL_RECOVERY_ENHANCER 0.0
20521 #endif
20522 
20523 #ifndef DEFAULT_TOOL_DEATH_REDUCTION
20524  #define DEFAULT_TOOL_DEATH_REDUCTION 0.0
20525 #endif
20526 
20527 #ifndef EPI_DEFAULT_VIRUS_PROB_INFECTION
20528  #define EPI_DEFAULT_VIRUS_PROB_INFECTION 1.0
20529 #endif
20530 
20531 #ifndef EPI_DEFAULT_VIRUS_PROB_RECOVERY
20532  #define EPI_DEFAULT_VIRUS_PROB_RECOVERY 0.1428
20533 #endif
20534 
20535 #ifndef EPI_DEFAULT_VIRUS_PROB_DEATH
20536  #define EPI_DEFAULT_VIRUS_PROB_DEATH 0.0
20537 #endif
20538 
20539 #ifndef EPI_DEFAULT_INCUBATION_DAYS
20540  #define EPI_DEFAULT_INCUBATION_DAYS 7.0
20541 #endif
20543 
20544 #ifdef EPI_DEBUG
20545  #define EPI_DEBUG_PRINTF printf_epiworld
20546 
20547  #define EPI_DEBUG_ERROR(etype, msg) \
20548  (etype)("[[epi-debug]] (error) " + std::string(msg));
20549 
20550  #define EPI_DEBUG_NOTIFY_ACTIVE() \
20551  EPI_DEBUG_PRINTF("DEBUGGING ON (compiled with EPI_DEBUG defined)%s\n", "");
20552 
20553  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect) \
20554  for (auto & v : vect) \
20555  if (static_cast<double>(v) < 0.0) \
20556  throw EPI_DEBUG_ERROR(std::logic_error, "A negative value not allowed.");
20557 
20558  #define EPI_DEBUG_SUM_DBL(vect, num) \
20559  double _epi_debug_sum = 0.0; \
20560  for (auto & v : vect) \
20561  { \
20562  _epi_debug_sum += static_cast<double>(v);\
20563  if (_epi_debug_sum > static_cast<double>(num)) \
20564  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
20565  }
20566 
20567  #define EPI_DEBUG_SUM_INT(vect, num) \
20568  int _epi_debug_sum = 0; \
20569  for (auto & v : vect) \
20570  { \
20571  _epi_debug_sum += static_cast<int>(v);\
20572  if (_epi_debug_sum > static_cast<int>(num)) \
20573  throw EPI_DEBUG_ERROR(std::logic_error, "The sum of elements not reached."); \
20574  }
20575 
20576  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c) \
20577  if (a.size() != b.size()) {\
20578  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
20579  EPI_DEBUG_PRINTF("Size of vector a: %lu\n", (a).size());\
20580  EPI_DEBUG_PRINTF("Size of vector b: %lu\n", (b).size());\
20581  throw EPI_DEBUG_ERROR(std::length_error, "The vectors do not match size."); \
20582  }\
20583  for (int _i = 0; _i < static_cast<int>(a.size()); ++_i) \
20584  if (a[_i] != b[_i]) {\
20585  EPI_DEBUG_PRINTF("In '%s'", std::string(c).c_str()); \
20586  EPI_DEBUG_PRINTF("Iterating the last 5 values%s:\n", ""); \
20587  for (int _j = std::max(0, static_cast<int>(_i) - 4); _j <= _i; ++_j) \
20588  { \
20589  EPI_DEBUG_PRINTF( \
20590  "a[%i]: %i; b[%i]: %i\n", \
20591  _j, \
20592  static_cast<int>(a[_j]), \
20593  _j, static_cast<int>(b[_j])); \
20594  } \
20595  throw EPI_DEBUG_ERROR(std::logic_error, "The vectors do not match."); \
20596  }
20597 
20598  #define EPI_DEBUG_FAIL_AT_TRUE(a,b) \
20599  if (a) \
20600  {\
20601  throw EPI_DEBUG_ERROR(std::logic_error, b); \
20602  }
20603 
20604  #define epiexception(a) std::logic_error
20605 #else
20606  #define EPI_DEBUG_PRINTF(fmt, ...)
20607  #define EPI_DEBUG_ERROR(fmt, ...)
20608  #define EPI_DEBUG_NOTIFY_ACTIVE()
20609  #define EPI_DEBUG_ALL_NON_NEGATIVE(vect)
20610  #define EPI_DEBUG_SUM_DBL(vect, num)
20611  #define EPI_DEBUG_SUM_INT(vect, num)
20612  #define EPI_DEBUG_VECTOR_MATCH_INT(a, b, c)
20613  #define EPI_DEBUG_FAIL_AT_TRUE(a, b) \
20614  if (a) \
20615  return false;
20616  #define epiexception(a) a
20617 #endif
20618 
20619 #if defined(EPI_DEBUG_NO_THREAD_ID) || (!defined(__OPENMP) && !defined(_OPENMP))
20620  #define EPI_GET_THREAD_ID() 0
20621 #else
20622  #define EPI_GET_THREAD_ID() omp_get_thread_num()
20623 #endif
20624 
20625 #endif
20626 /*//////////////////////////////////////////////////////////////////////////////
20628 
20629  End of -include/epiworld/config.hpp-
20630 
20633 
20634 
20635 /*//////////////////////////////////////////////////////////////////////////////
20637 
20638  Start of -include/epiworld/epiworld-macros.hpp-
20639 
20642 
20643 
20644 #ifndef EPIWORLD_MACROS_HPP
20645 #define EPIWORLD_MACROS_HPP
20646 
20651 #define EPI_NEW_TOOL(fname,tseq) inline epiworld_double \
20652 (fname)(\
20653  epiworld::Tool< tseq > & t, \
20654  epiworld::Agent< tseq > * p, \
20655  std::shared_ptr<epiworld::Virus< tseq >> v, \
20656  epiworld::Model< tseq > * m\
20657  )
20658 
20663 #define EPI_NEW_TOOL_LAMBDA(funname,tseq) \
20664  epiworld::ToolFun<tseq> funname = \
20665  [](epiworld::Tool<tseq> & t, \
20666  epiworld::Agent<tseq> * p, \
20667  std::shared_ptr<epiworld::Virus<tseq>> v, \
20668  epiworld::Model<tseq> * m) -> epiworld_double
20669 
20674 #define EPI_PARAMS(i) m->operator()(i)
20675 
20680 #define EPI_NEW_MUTFUN(funname,tseq) inline bool \
20681  (funname)(\
20682  epiworld::Agent<tseq> * p, \
20683  epiworld::Virus<tseq> & v, \
20684  epiworld::Model<tseq> * m )
20685 
20686 #define EPI_NEW_MUTFUN_LAMBDA(funname,tseq) \
20687  epiworld::MutFun<tseq> funname = \
20688  [](epiworld::Agent<tseq> * p, \
20689  epiworld::Virus<tseq> & v, \
20690  epiworld::Model<tseq> * m) -> void
20691 
20692 #define EPI_NEW_POSTRECOVERYFUN(funname,tseq) inline void \
20693  (funname)( \
20694  epiworld::Agent<tseq> * p, \
20695  epiworld::Virus<tseq> & v, \
20696  epiworld::Model<tseq> * m\
20697  )
20698 
20699 #define EPI_NEW_POSTRECOVERYFUN_LAMBDA(funname,tseq) \
20700  epiworld::PostRecoveryFun<tseq> funname = \
20701  [](epiworld::Agent<tseq> * p, \
20702  epiworld::Virus<tseq> & v , \
20703  epiworld::Model<tseq> * m) -> void
20704 
20705 #define EPI_NEW_VIRUSFUN(funname,tseq) inline epiworld_double \
20706  (funname)( \
20707  epiworld::Agent<tseq> * p, \
20708  epiworld::Virus<tseq> & v, \
20709  epiworld::Model<tseq> * m\
20710  )
20711 
20712 #define EPI_NEW_VIRUSFUN_LAMBDA(funname,TSeq) \
20713  epiworld::VirusFun<TSeq> funname = \
20714  [](epiworld::Agent<TSeq> * p, \
20715  epiworld::Virus<TSeq> & v, \
20716  epiworld::Model<TSeq> * m) -> epiworld_double
20717 
20718 #define EPI_RUNIF() m->runif()
20719 
20720 #define EPIWORLD_RUN(a) \
20721  if (a.get_verbose()) \
20722  { \
20723  printf_epiworld("Running the model...\n");\
20724  } \
20725  for (epiworld_fast_uint niter = 0; niter < a.get_ndays(); ++niter)
20726 
20727 #define EPI_TOKENPASTE(a,b) a ## b
20728 #define MPAR(num) *(m->EPI_TOKENPASTE(p,num))
20729 
20730 #define EPI_NEW_UPDATEFUN(funname,tseq) inline void \
20731  (funname)(epiworld::Agent<tseq> * p, epiworld::Model<tseq> * m)
20732 
20733 #define EPI_NEW_UPDATEFUN_LAMBDA(funname,tseq) \
20734  epiworld::UpdateFun<tseq> funname = \
20735  [](epiworld::Agent<tseq> * p, epiworld::Model<tseq> * m) -> void
20736 
20737 #define EPI_NEW_GLOBALFUN(funname,tseq) inline void \
20738  (funname)(epiworld::Model<tseq>* m)
20739 
20740 #define EPI_NEW_GLOBALFUN_LAMBDA(funname,tseq) \
20741  epiworld::GlobalFun<tseq> funname = \
20742  [](epiworld::Model<tseq>* m) -> void
20743 
20744 
20745 #define EPI_NEW_ENTITYTOAGENTFUN(funname,tseq) inline void \
20746  (funname)(epiworld::Entity<tseq> & e, epiworld::Model<tseq> * m)
20747 
20748 #define EPI_NEW_ENTITYTOAGENTFUN_LAMBDA(funname,tseq) \
20749  epiworld::EntityToAgentFun<tseq> funname = \
20750  [](epiworld::Entity<tseq> & e, epiworld::Model<tseq> * m) -> void
20751 
20752 // Use this to make it more efficient for storage if the type is small
20753 // and the pointer is not needed
20754 #define EPI_TYPENAME_TRAITS(tseq, bound) typename std::conditional< \
20755  sizeof( tseq ) <= sizeof( bound ), \
20756  tseq, \
20757  std::shared_ptr< tseq > \
20758  >::type
20759 
20760 #define EPI_IF_TSEQ_LESS_EQ_INT(tseq) \
20761  if constexpr (sizeof( tseq ) <= sizeof( int ))
20762 
20763 #define EPI_CHECK_COALESCE(proposed_, virus_tool_, alt_) \
20764  if (static_cast<int>(proposed_) == -99) {\
20765  if (static_cast<int>(virus_tool_) == -99) \
20766  (proposed_) = (alt_);\
20767  else (proposed_) = (virus_tool_);}
20768 
20769 #endif
20770 /*//////////////////////////////////////////////////////////////////////////////
20772 
20773  End of -include/epiworld/epiworld-macros.hpp-
20774 
20777 
20778 
20779 /*//////////////////////////////////////////////////////////////////////////////
20781 
20782  Start of -include/epiworld/entities-bones.hpp-
20783 
20786 
20787 
20788 #ifndef EPIWORLD_ENTITIES_BONES_HPP
20789 #define EPIWORLD_ENTITIES_BONES_HPP
20790 
20791 template<typename TSeq>
20792 class Virus;
20793 
20794 template<typename TSeq>
20795 class Agent;
20796 
20797 
20803 template<typename TSeq>
20804 class Entities {
20805  friend class Entity<TSeq>;
20806  friend class Agent<TSeq>;
20807 private:
20808  std::vector< Entity<TSeq> * > dat;
20809  const size_t n_entities;
20810 
20811 public:
20812 
20813  Entities() = delete;
20814  Entities(Agent<TSeq> & p);
20815 
20816  typename std::vector< Entity<TSeq> * >::iterator begin();
20817  typename std::vector< Entity<TSeq> * >::iterator end();
20818 
20819  Entity<TSeq> & operator()(size_t i);
20820  Entity<TSeq> & operator[](size_t i);
20821 
20822  size_t size() const noexcept;
20823 
20824  bool operator==(const Entities<TSeq> & other) const;
20825 
20826 };
20827 
20828 template<typename TSeq>
20829 inline Entities<TSeq>::Entities(Agent<TSeq> & p) :
20830  n_entities(p.get_n_entities())
20831 {
20832 
20833  dat.reserve(n_entities);
20834  for (size_t i = 0u; i < n_entities; ++i)
20835  dat.push_back(&p.get_entity(i));
20836 
20837 }
20838 
20839 template<typename TSeq>
20840 inline typename std::vector< Entity<TSeq>* >::iterator Entities<TSeq>::begin()
20841 {
20842 
20843  if (n_entities == 0u)
20844  return dat.end();
20845 
20846  return dat.begin();
20847 }
20848 
20849 template<typename TSeq>
20850 inline typename std::vector< Entity<TSeq>* >::iterator Entities<TSeq>::end()
20851 {
20852 
20853  return begin() + n_entities;
20854 }
20855 
20856 template<typename TSeq>
20857 inline Entity<TSeq> & Entities<TSeq>::operator()(size_t i)
20858 {
20859 
20860  if (i >= n_entities)
20861  throw std::range_error("Entity index out of range.");
20862 
20863  return *dat[i];
20864 
20865 }
20866 
20867 template<typename TSeq>
20868 inline Entity<TSeq> & Entities<TSeq>::operator[](size_t i)
20869 {
20870 
20871  return *dat[i];
20872 
20873 }
20874 
20875 template<typename TSeq>
20876 inline size_t Entities<TSeq>::size() const noexcept
20877 {
20878  return n_entities;
20879 }
20880 
20881 template<typename TSeq>
20882 inline bool Entities<TSeq>::operator==(const Entities<TSeq> & other) const
20883 {
20884 
20885  if (n_entities != other.n_entities)
20886  return false;
20887 
20888  for (size_t i = 0u; i < dat.size(); ++i)
20889  {
20890  if (dat[i] != other.dat[i])
20891  return false;
20892  }
20893 
20894  return true;
20895 }
20896 
20902 template<typename TSeq>
20903 class Entities_const {
20904  friend class Virus<TSeq>;
20905  friend class Agent<TSeq>;
20906 private:
20907  const std::vector< Entity<TSeq>* > dat;
20908  const size_t n_entities;
20909 
20910 public:
20911 
20912  Entities_const() = delete;
20913  Entities_const(const Agent<TSeq> & p);
20914 
20915  typename std::vector< Entity<TSeq>* >::const_iterator begin();
20916  typename std::vector< Entity<TSeq>* >::const_iterator end();
20917 
20918  const Entity<TSeq> & operator()(size_t i);
20919  const Entity<TSeq> & operator[](size_t i);
20920 
20921  size_t size() const noexcept;
20922 
20923  bool operator==(const Entities_const<TSeq> & other) const;
20924 
20925 };
20926 
20927 template<typename TSeq>
20928 inline Entities_const<TSeq>::Entities_const(const Agent<TSeq> & p) :
20929  n_entities(p.get_n_entities())
20930 {
20931 
20932  dat.reserve(n_entities);
20933  for (size_t i = 0u; i < n_entities; ++i)
20934  dat.push_back(&p.get_entity(i));
20935 
20936 }
20937 
20938 template<typename TSeq>
20939 inline typename std::vector< Entity<TSeq>* >::const_iterator Entities_const<TSeq>::begin() {
20940 
20941  if (n_entities == 0u)
20942  return dat.end();
20943 
20944  return dat.begin();
20945 }
20946 
20947 template<typename TSeq>
20948 inline typename std::vector< Entity<TSeq>* >::const_iterator Entities_const<TSeq>::end() {
20949 
20950  return begin() + n_entities;
20951 }
20952 
20953 template<typename TSeq>
20954 inline const Entity<TSeq> & Entities_const<TSeq>::operator()(size_t i)
20955 {
20956 
20957  if (i >= n_entities)
20958  throw std::range_error("Entity index out of range.");
20959 
20960  return *dat[i];
20961 
20962 }
20963 
20964 template<typename TSeq>
20965 inline const Entity<TSeq> & Entities_const<TSeq>::operator[](size_t i)
20966 {
20967 
20968  return *dat[i];
20969 
20970 }
20971 
20972 template<typename TSeq>
20973 inline size_t Entities_const<TSeq>::size() const noexcept
20974 {
20975  return n_entities;
20976 }
20977 
20978 template<typename TSeq>
20979 inline bool Entities_const<TSeq>::operator==(const Entities_const<TSeq> & other) const
20980 {
20981 
20982  if (n_entities != other.n_entities)
20983  return false;
20984 
20985  for (size_t i = 0u; i < dat.size(); ++i)
20986  {
20987  if (dat[i] != other.dat[i])
20988  return false;
20989  }
20990 
20991  return true;
20992 }
20993 
20994 
20995 #endif
20996 /*//////////////////////////////////////////////////////////////////////////////
20998 
20999  End of -include/epiworld/entities-bones.hpp-
21000 
21003 
21004 
21005 /*//////////////////////////////////////////////////////////////////////////////
21007 
21008  Start of -include/epiworld/agent-bones.hpp-
21009 
21012 
21013 
21014 #ifndef EPIWORLD_PERSON_BONES_HPP
21015 #define EPIWORLD_PERSON_BONES_HPP
21016 
21017 template<typename TSeq>
21018 class Model;
21019 
21020 template<typename TSeq>
21021 class Virus;
21022 
21023 template<typename TSeq>
21024 class Viruses;
21025 
21026 template<typename TSeq>
21027 class Viruses_const;
21028 
21029 template<typename TSeq>
21030 class Tool;
21031 
21032 template<typename TSeq>
21033 class Tools;
21034 
21035 template<typename TSeq>
21036 class Tools_const;
21037 
21038 template<typename TSeq>
21039 class Queue;
21040 
21041 template<typename TSeq>
21042 struct Event;
21043 
21044 template<typename TSeq>
21045 class Entity;
21046 
21047 template<typename TSeq>
21048 class Entities;
21049 
21050 template<typename TSeq>
21051 inline void default_add_virus(Event<TSeq> & a, Model<TSeq> * m);
21052 
21053 template<typename TSeq>
21054 inline void default_add_tool(Event<TSeq> & a, Model<TSeq> * m);
21055 
21056 template<typename TSeq>
21057 inline void default_add_entity(Event<TSeq> & a, Model<TSeq> * m);
21058 
21059 template<typename TSeq>
21060 inline void default_rm_virus(Event<TSeq> & a, Model<TSeq> * m);
21061 
21062 template<typename TSeq>
21063 inline void default_rm_tool(Event<TSeq> & a, Model<TSeq> * m);
21064 
21065 template<typename TSeq>
21066 inline void default_rm_entity(Event<TSeq> & a, Model<TSeq> * m);
21067 
21068 template<typename TSeq>
21069 inline void default_change_state(Event<TSeq> & a, Model<TSeq> * m);
21070 
21071 
21072 
21078 template<typename TSeq>
21079 class Agent {
21080  friend class Model<TSeq>;
21081  friend class Virus<TSeq>;
21082  friend class Tool<TSeq>;
21083  friend class Tools<TSeq>;
21084  friend class Tools_const<TSeq>;
21085  friend class Queue<TSeq>;
21086  friend class Entities<TSeq>;
21087  friend class AgentsSample<TSeq>;
21088  friend void default_add_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21089  friend void default_add_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21090  friend void default_add_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21091  friend void default_rm_virus<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21092  friend void default_rm_tool<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21093  friend void default_rm_entity<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21094  friend void default_change_state<TSeq>(Event<TSeq> & a, Model<TSeq> * m);
21095 private:
21096 
21097  Model<TSeq> * model;
21098 
21099  std::vector< size_t > * neighbors = nullptr;
21100  std::vector< size_t > * neighbors_locations = nullptr;
21101  size_t n_neighbors = 0u;
21102 
21103  std::vector< size_t > entities;
21104  std::vector< size_t > entities_locations;
21105  size_t n_entities = 0u;
21106 
21107  unsigned int state = 0u;
21108  unsigned int state_prev = 0u; ///< For accounting, if need to undo a change.
21109 
21110  int state_last_changed = -1; ///< Last time the agent was updated.
21111  int id = -1;
21112 
21113  VirusPtr<TSeq> virus = nullptr;
21114 
21115  std::vector< ToolPtr<TSeq> > tools;
21116  unsigned int n_tools = 0u;
21117 
21118 public:
21119 
21120  Agent();
21121  Agent(Agent<TSeq> && p);
21122  Agent(const Agent<TSeq> & p);
21123  Agent<TSeq> & operator=(const Agent<TSeq> & other_agent);
21124  ~Agent();
21125 
21137  void add_tool(
21138  ToolPtr<TSeq> & tool,
21139  Model<TSeq> * model,
21140  epiworld_fast_int state_new = -99,
21141  epiworld_fast_int queue = -99
21142  );
21143 
21144  void add_tool(
21145  const Tool<TSeq> & tool,
21146  Model<TSeq> * model,
21147  epiworld_fast_int state_new = -99,
21148  epiworld_fast_int queue = -99
21149  );
21150 
21151  void set_virus(
21152  VirusPtr<TSeq> & virus,
21153  Model<TSeq> * model,
21154  epiworld_fast_int state_new = -99,
21155  epiworld_fast_int queue = -99
21156  );
21157 
21158  void set_virus(
21159  const Virus<TSeq> & virus,
21160  Model<TSeq> * model,
21161  epiworld_fast_int state_new = -99,
21162  epiworld_fast_int queue = -99
21163  );
21164 
21165  void add_entity(
21166  Entity<TSeq> & entity,
21167  Model<TSeq> * model,
21168  epiworld_fast_int state_new = -99,
21169  epiworld_fast_int queue = -99
21170  );
21171 
21172  void rm_tool(
21173  epiworld_fast_uint tool_idx,
21174  Model<TSeq> * model,
21175  epiworld_fast_int state_new = -99,
21176  epiworld_fast_int queue = -99
21177  );
21178 
21179  void rm_tool(
21180  ToolPtr<TSeq> & tool,
21181  Model<TSeq> * model,
21182  epiworld_fast_int state_new = -99,
21183  epiworld_fast_int queue = -99
21184  );
21185 
21186  void rm_virus(
21187  Model<TSeq> * model,
21188  epiworld_fast_int state_new = -99,
21189  epiworld_fast_int queue = -99
21190  );
21191 
21192  void rm_entity(
21193  epiworld_fast_uint entity_idx,
21194  Model<TSeq> * model,
21195  epiworld_fast_int state_new = -99,
21196  epiworld_fast_int queue = -99
21197  );
21198 
21199  void rm_entity(
21200  Entity<TSeq> & entity,
21201  Model<TSeq> * model,
21202  epiworld_fast_int state_new = -99,
21203  epiworld_fast_int queue = -99
21204  );
21205 
21206  void rm_agent_by_virus(Model<TSeq> * model); ///< Agent removed by virus
21208 
21216  epiworld_double get_susceptibility_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
21217  epiworld_double get_transmission_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
21218  epiworld_double get_recovery_enhancer(VirusPtr<TSeq> v, Model<TSeq> * model);
21219  epiworld_double get_death_reduction(VirusPtr<TSeq> v, Model<TSeq> * model);
21221 
21222  int get_id() const; ///< Id of the individual
21223 
21224  VirusPtr<TSeq> & get_virus();
21225  const VirusPtr<TSeq> & get_virus() const;
21226 
21227  ToolPtr<TSeq> & get_tool(int i);
21228  Tools<TSeq> get_tools();
21229  const Tools_const<TSeq> get_tools() const;
21230  size_t get_n_tools() const noexcept;
21231 
21232  void mutate_virus();
21233  void add_neighbor(
21234  Agent<TSeq> & p,
21235  bool check_source = true,
21236  bool check_target = true
21237  );
21238 
21246  void swap_neighbors(
21247  Agent<TSeq> & other,
21248  size_t n_this,
21249  size_t n_other
21250  );
21251 
21252  std::vector< Agent<TSeq> * > get_neighbors();
21253  size_t get_n_neighbors() const;
21254 
21255  void change_state(
21256  Model<TSeq> * model,
21257  epiworld_fast_uint new_state,
21258  epiworld_fast_int queue = 0
21259  );
21260 
21261  const unsigned int & get_state() const;
21262 
21263  void reset();
21264 
21265  bool has_tool(epiworld_fast_uint t) const;
21266  bool has_tool(std::string name) const;
21267  bool has_tool(const Tool<TSeq> & t) const;
21268  bool has_virus(epiworld_fast_uint t) const;
21269  bool has_virus(std::string name) const;
21270  bool has_virus(const Virus<TSeq> & v) const;
21271  bool has_entity(epiworld_fast_uint t) const;
21272  bool has_entity(std::string name) const;
21273 
21274  void print(bool compressed = false) const;
21275 
21292  double & operator()(size_t j);
21293  double & operator[](size_t j);
21294  double operator()(size_t j) const;
21295  double operator[](size_t j) const;
21297 
21298  Entities<TSeq> get_entities();
21299  const Entities_const<TSeq> get_entities() const;
21300  const Entity<TSeq> & get_entity(size_t i) const;
21301  Entity<TSeq> & get_entity(size_t i);
21302  size_t get_n_entities() const;
21303 
21304  bool operator==(const Agent<TSeq> & other) const;
21305  bool operator!=(const Agent<TSeq> & other) const {return !operator==(other);};
21306 
21307 };
21308 
21309 
21310 
21311 #endif
21312 /*//////////////////////////////////////////////////////////////////////////////
21314 
21315  End of -include/epiworld/agent-bones.hpp-
21316 
21319 
21320 
21321 /*//////////////////////////////////////////////////////////////////////////////
21323 
21324  Start of -include/epiworld/agent-events-meat.hpp-
21325 
21328 
21329 
21330 #ifndef EPIWORLD_AGENT_EVENTS_MEAT_HPP
21331 #define EPIWORLD_AGENT_EVENTS_MEAT_HPP
21332 
21333 
21334 template<typename TSeq>
21335 inline void default_add_virus(Event<TSeq> & a, Model<TSeq> * m)
21336 {
21337 
21338  Agent<TSeq> * p = a.agent;
21339  VirusPtr<TSeq> & v = a.virus;
21340 
21341  m->get_db().record_transmission(
21342  v->get_agent() ? v->get_agent()->get_id() : -1,
21343  p->get_id(),
21344  v->get_id(),
21345  v->get_date()
21346  );
21347 
21348  p->virus = std::move(v);
21349  p->virus->set_date(m->today());
21350  p->virus->set_agent(p);
21351 
21352  // Change of state needs to be recorded and updated on the
21353  // tools.
21354  if ((a.new_state != -99) && (static_cast<int>(p->state) != a.new_state))
21355  {
21356  auto & db = m->get_db();
21357  db.update_state(p->state_prev, a.new_state);
21358 
21359  for (size_t i = 0u; i < p->n_tools; ++i)
21360  db.update_tool(
21361  p->tools[i]->get_id(),
21362  p->state_prev,
21363  a.new_state
21364  );
21365  }
21366 
21367  // Lastly, we increase the daily count of the virus
21368  #ifdef EPI_DEBUG
21369  m->get_db().today_virus.at(p->virus->get_id()).at(
21370  a.new_state != -99 ? a.new_state : p->state
21371  )++;
21372  #else
21373  m->get_db().today_virus[p->virus->get_id()][
21374  a.new_state != -99 ? a.new_state : p->state
21375  ]++;
21376  #endif
21377 
21378 }
21379 
21380 template<typename TSeq>
21381 inline void default_add_tool(Event<TSeq> & a, Model<TSeq> * m)
21382 {
21383 
21384  Agent<TSeq> * p = a.agent;
21385  ToolPtr<TSeq> & t = a.tool;
21386 
21387  // Update tool accounting
21388  p->n_tools++;
21389  size_t n_tools = p->n_tools;
21390 
21391  if (n_tools <= p->tools.size())
21392  p->tools[n_tools - 1] = std::move(t);
21393  else
21394  p->tools.emplace_back(std::move(t));
21395 
21396  n_tools--;
21397 
21398  p->tools[n_tools]->set_date(m->today());
21399  p->tools[n_tools]->set_agent(p, n_tools);
21400 
21401  // Change of state needs to be recorded and updated on the
21402  // tools.
21403  if ((a.new_state != -99) && static_cast<int>(p->state) != a.new_state)
21404  {
21405  auto & db = m->get_db();
21406  db.update_state(p->state_prev, a.new_state);
21407 
21408  if (p->virus)
21409  db.update_virus(
21410  p->virus->get_id(),
21411  p->state_prev,
21412  a.new_state
21413  );
21414  }
21415 
21416  m->get_db().today_tool[p->tools.back()->get_id()][
21417  a.new_state != -99 ? a.new_state : p->state
21418  ]++;
21419 
21420 
21421 }
21422 
21423 template<typename TSeq>
21424 inline void default_rm_virus(Event<TSeq> & a, Model<TSeq> * model)
21425 {
21426 
21427  Agent<TSeq> * p = a.agent;
21428  VirusPtr<TSeq> & v = a.virus;
21429 
21430  // Calling the virus action over the removed virus
21431  v->post_recovery(model);
21432 
21433  p->virus = nullptr;
21434 
21435  // Change of state needs to be recorded and updated on the
21436  // tools.
21437  if ((a.new_state != -99) && (static_cast<int>(p->state) != a.new_state))
21438  {
21439  auto & db = model->get_db();
21440  db.update_state(p->state_prev, a.new_state);
21441 
21442  for (size_t i = 0u; i < p->n_tools; ++i)
21443  db.update_tool(
21444  p->tools[i]->get_id(),
21445  p->state_prev,
21446  a.new_state
21447  );
21448  }
21449 
21450  // The counters of the virus only needs to decrease.
21451  // We use the previous state of the agent as that was
21452  // the state when the virus was added.
21453  #ifdef EPI_DEBUG
21454  model->get_db().today_virus.at(v->get_id()).at(p->state_prev)--;
21455  #else
21456  model->get_db().today_virus[v->get_id()][p->state_prev]--;
21457  #endif
21458 
21459 
21460  return;
21461 
21462 }
21463 
21464 template<typename TSeq>
21465 inline void default_rm_tool(Event<TSeq> & a, Model<TSeq> * m)
21466 {
21467 
21468  Agent<TSeq> * p = a.agent;
21469  ToolPtr<TSeq> & t = a.agent->tools[a.tool->pos_in_agent];
21470 
21471  if (--p->n_tools > 0)
21472  {
21473  p->tools[p->n_tools]->pos_in_agent = t->pos_in_agent;
21474  std::swap(
21475  p->tools[t->pos_in_agent],
21476  p->tools[p->n_tools]
21477  );
21478  }
21479 
21480  // Change of state needs to be recorded and updated on the
21481  // tools.
21482  if ((a.new_state != -99) && (static_cast<int>(p->state) != a.new_state))
21483  {
21484  auto & db = m->get_db();
21485  db.update_state(p->state_prev, a.new_state);
21486 
21487  if (p->virus)
21488  db.update_virus(
21489  p->virus->get_id(),
21490  p->state_prev,
21491  a.new_state
21492  );
21493  }
21494 
21495  // Lastly, we increase the daily count of the tool.
21496  // Like rm_virus, we use the previous state of the agent
21497  // as that was the state when the tool was added.
21498  #ifdef EPI_DEBUG
21499  m->get_db().today_tool.at(t->get_id()).at(p->state_prev)--;
21500  #else
21501  m->get_db().today_tool[t->get_id()][p->state_prev]--;
21502  #endif
21503 
21504  return;
21505 
21506 }
21507 
21508 template<typename TSeq>
21509 inline void default_change_state(Event<TSeq> & a, Model<TSeq> * m)
21510 {
21511 
21512  Agent<TSeq> * p = a.agent;
21513 
21514  if ((a.new_state != -99) && (static_cast<int>(p->state) != a.new_state))
21515  {
21516  auto & db = m->get_db();
21517  db.update_state(p->state_prev, a.new_state);
21518 
21519  if (p->virus)
21520  db.update_virus(
21521  p->virus->get_id(), p->state_prev, a.new_state
21522  );
21523 
21524  for (size_t i = 0u; i < p->n_tools; ++i)
21525  db.update_tool(
21526  p->tools[i]->get_id(),
21527  p->state_prev,
21528  a.new_state
21529  );
21530 
21531  }
21532 
21533 }
21534 
21535 template<typename TSeq>
21536 inline void default_add_entity(Event<TSeq> & a, Model<TSeq> *)
21537 {
21538 
21539  Agent<TSeq> * p = a.agent;
21540  Entity<TSeq> * e = a.entity;
21541 
21542  // Checking the agent and the entity are not linked
21543  if ((p->get_n_entities() > 0) && (e->size() > 0))
21544  {
21545 
21546  if (p->get_n_entities() > e->size()) // Slower search through the agent
21547  {
21548  for (size_t i = 0u; i < e->size(); ++i)
21549  if(static_cast<int>(e->operator[](i)) == p->get_id())
21550  throw std::logic_error("An entity cannot be reassigned to an agent.");
21551  }
21552  else // Slower search through the entity
21553  {
21554  for (size_t i = 0u; i < p->get_n_entities(); ++i)
21555  if(p->get_entity(i).get_id() == e->get_id())
21556  throw std::logic_error("An entity cannot be reassigned to an agent.");
21557  }
21558 
21559  // It means that agent and entity were not associated.
21560  }
21561 
21562  // Adding the entity to the agent
21563  if (++p->n_entities <= p->entities.size())
21564  {
21565 
21566  p->entities[p->n_entities - 1] = e->get_id();
21567  p->entities_locations[p->n_entities - 1] = e->n_agents;
21568 
21569  } else
21570  {
21571  p->entities.push_back(e->get_id());
21572  p->entities_locations.push_back(e->n_agents);
21573  }
21574 
21575  // Adding the agent to the entity
21576  // Adding the entity to the agent
21577  if (++e->n_agents <= e->agents.size())
21578  {
21579 
21580  e->agents[e->n_agents - 1] = p->get_id();
21581  // Adjusted by '-1' since the list of entities in the agent just grew.
21582  e->agents_location[e->n_agents - 1] = p->n_entities - 1;
21583 
21584  } else
21585  {
21586  e->agents.push_back(p->get_id());
21587  e->agents_location.push_back(p->n_entities - 1);
21588  }
21589 
21590  // Today was the last modification
21591  // e->date_last_add_or_remove = m->today();
21592 
21593 }
21594 
21595 template<typename TSeq>
21596 inline void default_rm_entity(Event<TSeq> & a, Model<TSeq> * m)
21597 {
21598 
21599  Agent<TSeq> * p = a.agent;
21600  Entity<TSeq> * e = a.entity;
21601  size_t idx_agent_in_entity = a.idx_agent;
21602  size_t idx_entity_in_agent = a.idx_object;
21603 
21604  if (--p->n_entities > 0)
21605  {
21606 
21607  // When we move the end entity to the new location, the
21608  // moved entity needs to reflect the change, i.e., where the
21609  // entity will now be located in the agent
21610  size_t agent_location_in_last_entity =
21611  p->entities_locations[p->n_entities];
21612 
21613  Entity<TSeq> * last_entity =
21614  &m->get_entity(p->entities[p->n_entities]); ///< Last entity of the agent
21615 
21616  // The end entity will be located where the removed was
21617  last_entity->agents_location[agent_location_in_last_entity] =
21618  idx_entity_in_agent;
21619 
21620  // We now make the swap
21621  std::swap(
21622  p->entities[p->n_entities],
21623  p->entities[idx_entity_in_agent]
21624  );
21625 
21626  }
21627 
21628  if (--e->n_agents > 0)
21629  {
21630 
21631  // When we move the end agent to the new location, the
21632  // moved agent needs to reflect the change, i.e., where the
21633  // agent will now be located in the entity
21634  size_t entity_location_in_last_agent = e->agents_location[e->n_agents];
21635 
21636  Agent<TSeq> * last_agent =
21637  &m->get_agents()[e->agents[e->n_agents]]; ///< Last agent of the entity
21638 
21639  // The end entity will be located where the removed was
21640  last_agent->entities_locations[entity_location_in_last_agent] =
21641  idx_agent_in_entity;
21642 
21643  // We now make the swap
21644  std::swap(
21645  e->agents[e->n_agents],
21646  e->agents[idx_agent_in_entity]
21647  );
21648 
21649  }
21650 
21651  // Setting the date of the last removal
21652  // e->date_last_add_or_remove = m->today();
21653 
21654  return;
21655 
21656 };
21657 
21658 #endif
21659 /*//////////////////////////////////////////////////////////////////////////////
21661 
21662  End of -include/epiworld/agent-events-meat.hpp-
21663 
21666 
21667 
21668 
21669 // To large to add directly here
21670 
21671 template<typename TSeq>
21672 inline Agent<TSeq>::Agent() {}
21673 
21674 template<typename TSeq>
21675 inline Agent<TSeq>::Agent(Agent<TSeq> && p) :
21676  model(p.model),
21677  neighbors(std::move(p.neighbors)),
21678  neighbors_locations(std::move(p.neighbors_locations)),
21679  n_neighbors(p.n_neighbors),
21680  entities(std::move(p.entities)),
21681  entities_locations(std::move(p.entities_locations)),
21682  n_entities(p.n_entities),
21683  state(p.state),
21684  state_prev(p.state_prev),
21685  state_last_changed(p.state_last_changed),
21686  id(p.id),
21687  tools(std::move(p.tools)), /// Needs to be adjusted
21688  n_tools(p.n_tools)
21689 {
21690 
21691  state = p.state;
21692  id = p.id;
21693 
21694  // Dealing with the virus
21695  if (p.virus != nullptr)
21696  {
21697  virus = std::move(p.virus);
21698  virus->set_agent(this);
21699  }
21700 
21701  int loc = 0;
21702  for (auto & t : tools)
21703  {
21704 
21705  // Will create a copy of the virus, with the exeption of
21706  // the virus code
21707  t->agent = this;
21708  t->pos_in_agent = loc++;
21709 
21710  }
21711 
21712 }
21713 
21714 template<typename TSeq>
21715 inline Agent<TSeq>::Agent(const Agent<TSeq> & p) :
21716  model(p.model),
21717  neighbors(nullptr),
21718  neighbors_locations(nullptr),
21719  n_neighbors(p.n_neighbors),
21720  entities(p.entities),
21721  entities_locations(p.entities_locations),
21722  n_entities(p.n_entities)
21723 {
21724 
21725  if (n_neighbors > 0u)
21726  {
21727  neighbors = new std::vector< size_t >(*p.neighbors);
21728  neighbors_locations = new std::vector< size_t >(*p.neighbors_locations);
21729  }
21730 
21731  state = p.state;
21732  id = p.id;
21733 
21734  // Dealing with the virus
21735  if (p.virus != nullptr)
21736  {
21737  virus = std::make_shared<Virus<TSeq>>(*p.virus);
21738  virus->set_agent(this);
21739  }
21740 
21741 
21742  tools.reserve(p.get_n_tools());
21743  n_tools = tools.size();
21744  for (size_t i = 0u; i < n_tools; ++i)
21745  {
21746 
21747  // Will create a copy of the virus, with the exeption of
21748  // the virus code
21749  tools.emplace_back(std::make_shared<Tool<TSeq>>(*p.tools[i]));
21750  tools.back()->set_agent(this, i);
21751 
21752  }
21753 
21754 }
21755 
21756 template<typename TSeq>
21757 inline Agent<TSeq> & Agent<TSeq>::operator=(
21758  const Agent<TSeq> & other_agent
21759 )
21760 {
21761 
21762  model = other_agent.model;
21763 
21764  n_neighbors = other_agent.n_neighbors;
21765  if (neighbors != nullptr)
21766  {
21767  delete neighbors;
21768  delete neighbors_locations;
21769  }
21770 
21771  if (other_agent.n_neighbors > 0u)
21772  {
21773  neighbors = new std::vector< size_t >(*other_agent.neighbors);
21774  neighbors_locations = new std::vector< size_t >(*other_agent.neighbors_locations);
21775  }
21776  else
21777  {
21778  neighbors = nullptr;
21779  neighbors_locations = nullptr;
21780  }
21781 
21782  entities = other_agent.entities;
21783  entities_locations = other_agent.entities_locations;
21784  n_entities = other_agent.n_entities;
21785 
21786  state = other_agent.state;
21787  state_prev = other_agent.state_prev;
21788  state_last_changed = other_agent.state_last_changed;
21789  id = other_agent.id;
21790 
21791  if (other_agent.virus != nullptr)
21792  {
21793  virus = std::make_shared<Virus<TSeq>>(*other_agent.virus);
21794  virus->set_agent(this);
21795  } else
21796  virus = nullptr;
21797 
21798  n_tools = other_agent.n_tools;
21799  for (size_t i = 0u; i < n_tools; ++i)
21800  {
21801  tools[i] = std::make_shared<Tool<TSeq>>(*other_agent.tools[i]);
21802  tools[i]->set_agent(this, i);
21803  }
21804 
21805  return *this;
21806 
21807 }
21808 
21809 template<typename TSeq>
21810 inline Agent<TSeq>::~Agent()
21811 {
21812 
21813  if (neighbors != nullptr)
21814  {
21815  delete neighbors;
21816  delete neighbors_locations;
21817  }
21818 
21819 }
21820 
21821 template<typename TSeq>
21822 inline void Agent<TSeq>::add_tool(
21823  ToolPtr<TSeq> & tool,
21824  Model<TSeq> * model,
21825  epiworld_fast_int state_new,
21826  epiworld_fast_int queue
21827 ) {
21828 
21829  // Checking the virus exists
21830  if (tool->get_id() >= static_cast<int>(model->get_db().get_n_tools()))
21831  throw std::range_error("The tool with id: " + std::to_string(tool->get_id()) +
21832  " has not been registered. There are only " + std::to_string(model->get_n_tools()) +
21833  " included in the model.");
21834 
21835  model->events_add(
21836  this, nullptr, tool, nullptr, state_new, queue, default_add_tool<TSeq>, -1, -1
21837  );
21838 
21839 }
21840 
21841 template<typename TSeq>
21842 inline void Agent<TSeq>::add_tool(
21843  const Tool<TSeq> & tool,
21844  Model<TSeq> * model,
21845  epiworld_fast_int state_new,
21846  epiworld_fast_int queue
21847 )
21848 {
21849  ToolPtr<TSeq> tool_ptr = std::make_shared< Tool<TSeq> >(tool);
21850  add_tool(tool_ptr, model, state_new, queue);
21851 }
21852 
21853 template<typename TSeq>
21854 inline void Agent<TSeq>::set_virus(
21855  VirusPtr<TSeq> & virus,
21856  Model<TSeq> * model,
21857  epiworld_fast_int state_new,
21858  epiworld_fast_int queue
21859 )
21860 {
21861 
21862  // Checking the virus exists
21863  if (virus->get_id() >= static_cast<int>(model->get_db().get_n_viruses()))
21864  throw std::range_error("The virus with id: " + std::to_string(virus->get_id()) +
21865  " has not been registered. There are only " + std::to_string(model->get_n_viruses()) +
21866  " included in the model.");
21867 
21868  if (state_new == -99)
21869  virus->get_state(&state_new, nullptr, nullptr);
21870 
21871  if (queue == -99)
21872  virus->get_queue(&queue, nullptr, nullptr);
21873 
21874  model->events_add(
21875  this, virus, nullptr, nullptr, state_new, queue, default_add_virus<TSeq>, -1, -1
21876  );
21877 
21878 }
21879 
21880 template<typename TSeq>
21881 inline void Agent<TSeq>::set_virus(
21882  const Virus<TSeq> & virus,
21883  Model<TSeq> * model,
21884  epiworld_fast_int state_new,
21885  epiworld_fast_int queue
21886 )
21887 {
21888  VirusPtr<TSeq> virus_ptr = std::make_shared< Virus<TSeq> >(virus);
21889  set_virus(virus_ptr, model, state_new, queue);
21890 }
21891 
21892 template<typename TSeq>
21893 inline void Agent<TSeq>::add_entity(
21894  Entity<TSeq> & entity,
21895  Model<TSeq> * model,
21896  epiworld_fast_int state_new,
21897  epiworld_fast_int queue
21898 )
21899 {
21900 
21901  if (model != nullptr)
21902  {
21903 
21904  model->events_add(
21905  this, nullptr, nullptr, &entity, state_new, queue, default_add_entity<TSeq>, -1, -1
21906  );
21907 
21908  }
21909  else // If no model is passed, then we assume that we only need to add the
21910  // model entity
21911  {
21912 
21913  auto nullvirus = VirusPtr<TSeq>(nullptr);
21914  auto nulltool = ToolPtr<TSeq>(nullptr);
21915  auto call = EventFun<TSeq>(default_add_entity<TSeq>);
21916 
21917  Event<TSeq> a(
21918  this,
21919  nullvirus,
21920  nulltool,
21921  &entity, state_new, queue,
21922  call,
21923  -1, -1
21924  );
21925 
21926  default_add_entity(a, model); /* passing model makes nothing */
21927 
21928  }
21929 
21930 }
21931 
21932 template<typename TSeq>
21933 inline void Agent<TSeq>::rm_tool(
21934  epiworld_fast_uint tool_idx,
21935  Model<TSeq> * model,
21936  epiworld_fast_int state_new,
21937  epiworld_fast_int queue
21938 )
21939 {
21940 
21941  if (tool_idx >= n_tools)
21942  throw std::range_error(
21943  "The Tool you want to remove is out of range. This Agent only has " +
21944  std::to_string(n_tools) + " tools."
21945  );
21946 
21947  model->events_add(
21948  this, nullptr, tools[tool_idx], nullptr, state_new, queue, default_rm_tool<TSeq>, -1, -1
21949  );
21950 
21951 }
21952 
21953 template<typename TSeq>
21954 inline void Agent<TSeq>::rm_tool(
21955  ToolPtr<TSeq> & tool,
21956  Model<TSeq> * model,
21957  epiworld_fast_int state_new,
21958  epiworld_fast_int queue
21959 )
21960 {
21961 
21962  if (tool->agent != this)
21963  throw std::logic_error("Cannot remove a virus from another agent!");
21964 
21965  model->events_add(
21966  this, nullptr, tool, nullptr, state_new, queue, default_rm_tool<TSeq>, -1, -1
21967  );
21968 
21969 }
21970 
21971 template<typename TSeq>
21972 inline void Agent<TSeq>::rm_virus(
21973  Model<TSeq> * model,
21974  epiworld_fast_int state_new,
21975  epiworld_fast_int queue
21976 )
21977 {
21978 
21979  if (virus == nullptr)
21980  throw std::logic_error(
21981  "There is no virus to remove here!"
21982  );
21983 
21984  if (state_new == -99)
21985  virus->get_state(nullptr, &state_new, nullptr);
21986 
21987  if (queue == -99)
21988  virus->get_queue(nullptr, &queue, nullptr);
21989 
21990  model->events_add(
21991  this, virus, nullptr, nullptr,
21992  state_new,
21993  queue,
21994  default_rm_virus<TSeq>, -1, -1
21995  );
21996 
21997 }
21998 
21999 template<typename TSeq>
22000 inline void Agent<TSeq>::rm_entity(
22001  epiworld_fast_uint entity_idx,
22002  Model<TSeq> * model,
22003  epiworld_fast_int state_new,
22004  epiworld_fast_int queue
22005 )
22006 {
22007 
22008  if (entity_idx >= n_entities)
22009  throw std::range_error(
22010  "The Entity you want to remove is out of range. This Agent only has " +
22011  std::to_string(n_entities) + " entitites."
22012  );
22013  else if (n_entities == 0u)
22014  throw std::logic_error(
22015  "There is entity to remove here!"
22016  );
22017 
22018  model->events_add(
22019  this,
22020  nullptr,
22021  nullptr,
22022  &model->get_entity(entity_idx),
22023  state_new,
22024  queue,
22025  default_rm_entity<TSeq>,
22026  entities_locations[entity_idx],
22027  entity_idx
22028  );
22029 }
22030 
22031 template<typename TSeq>
22032 inline void Agent<TSeq>::rm_entity(
22033  Entity<TSeq> & entity,
22034  Model<TSeq> * model,
22035  epiworld_fast_int state_new,
22036  epiworld_fast_int queue
22037 )
22038 {
22039 
22040  // Looking for entity location in the agent
22041  int entity_idx = -1;
22042  for (size_t i = 0u; i < n_entities; ++i)
22043  {
22044  if (static_cast<int>(entities[i]) == entity.get_id())
22045  {
22046  entity_idx = i;
22047  break;
22048  }
22049  }
22050 
22051  if (entity_idx == -1)
22052  throw std::logic_error(
22053  std::string("The agent ") +
22054  std::to_string(id) +
22055  std::string(" is not associated with entity \"") +
22056  entity.get_name() +
22057  std::string("\".")
22058  );
22059 
22060  model->events_add(
22061  this,
22062  nullptr,
22063  nullptr,
22064  &model->entities[entity.get_id()],
22065  state_new,
22066  queue,
22067  default_rm_entity<TSeq>,
22068  entities_locations[entity_idx],
22069  entity_idx
22070  );
22071 }
22072 
22073 template<typename TSeq>
22075  Model<TSeq> * model
22076 )
22077 {
22078 
22079  model->events_add(
22080  this, virus, nullptr, nullptr,
22081  virus->state_removed,
22082  virus->queue_removed,
22083  default_rm_virus<TSeq>, -1, -1
22084  );
22085 
22086 }
22087 
22088 template<typename TSeq>
22089 inline epiworld_double Agent<TSeq>::get_susceptibility_reduction(
22090  VirusPtr<TSeq> v,
22091  Model<TSeq> * model
22092 ) {
22093 
22094  return model->susceptibility_reduction_mixer(this, v, model);
22095 }
22096 
22097 template<typename TSeq>
22098 inline epiworld_double Agent<TSeq>::get_transmission_reduction(
22099  VirusPtr<TSeq> v,
22100  Model<TSeq> * model
22101 ) {
22102  return model->transmission_reduction_mixer(this, v, model);
22103 }
22104 
22105 template<typename TSeq>
22106 inline epiworld_double Agent<TSeq>::get_recovery_enhancer(
22107  VirusPtr<TSeq> v,
22108  Model<TSeq> * model
22109 ) {
22110  return model->recovery_enhancer_mixer(this, v, model);
22111 }
22112 
22113 template<typename TSeq>
22114 inline epiworld_double Agent<TSeq>::get_death_reduction(
22115  VirusPtr<TSeq> v,
22116  Model<TSeq> * model
22117 ) {
22118  return model->death_reduction_mixer(this, v, model);
22119 }
22120 
22121 template<typename TSeq>
22122 inline int Agent<TSeq>::get_id() const
22123 {
22124  return id;
22125 }
22126 
22127 template<typename TSeq>
22128 inline VirusPtr<TSeq> & Agent<TSeq>::get_virus() {
22129  return virus;
22130 }
22131 
22132 template<typename TSeq>
22133 inline const VirusPtr<TSeq> & Agent<TSeq>::get_virus() const {
22134  return virus;
22135 }
22136 
22137 
22138 template<typename TSeq>
22140  return Tools<TSeq>(*this);
22141 }
22142 
22143 template<typename TSeq>
22144 inline const Tools_const<TSeq> Agent<TSeq>::get_tools() const {
22145  return Tools_const<TSeq>(*this);
22146 }
22147 
22148 template<typename TSeq>
22149 inline ToolPtr<TSeq> & Agent<TSeq>::get_tool(int i)
22150 {
22151  return tools.at(i);
22152 }
22153 
22154 template<typename TSeq>
22155 inline size_t Agent<TSeq>::get_n_tools() const noexcept
22156 {
22157  return n_tools;
22158 }
22159 
22160 template<typename TSeq>
22161 inline void Agent<TSeq>::mutate_virus()
22162 {
22163 
22164  virus->mutate();
22165 
22166 }
22167 
22168 template<typename TSeq>
22169 inline void Agent<TSeq>::add_neighbor(
22170  Agent<TSeq> & p,
22171  bool check_source,
22172  bool check_target
22173 ) {
22174  // Can we find the neighbor?
22175  bool found = false;
22176 
22177  if (neighbors == nullptr)
22178  {
22179  neighbors = new std::vector< size_t >();
22180  neighbors_locations = new std::vector< size_t >();
22181  }
22182 
22183  if (check_source && neighbors)
22184  {
22185 
22186  for (auto & n: *neighbors)
22187  if (static_cast<int>(n) == p.get_id())
22188  {
22189  found = true;
22190  break;
22191  }
22192 
22193  }
22194 
22195  // Three things going on here:
22196  // - Where in the neighbor will this be
22197  // - What is the neighbor's id
22198  // - Increasing the number of neighbors
22199  if (!found)
22200  {
22201 
22202  neighbors_locations->push_back(p.get_n_neighbors());
22203  neighbors->push_back(p.get_id());
22204  n_neighbors++;
22205 
22206  }
22207 
22208 
22209  found = false;
22210  if (check_target && p.neighbors)
22211  {
22212 
22213  for (auto & n: *p.neighbors)
22214  if (static_cast<int>(n) == id)
22215  {
22216  found = true;
22217  break;
22218  }
22219 
22220  }
22221 
22222  if (!found)
22223  {
22224 
22225  if (p.neighbors == nullptr)
22226  {
22227  p.neighbors = new std::vector< size_t >();
22228  p.neighbors_locations = new std::vector< size_t >();
22229  }
22230 
22231  p.neighbors_locations->push_back(n_neighbors - 1);
22232  p.neighbors->push_back(id);
22233  p.n_neighbors++;
22234 
22235  }
22236 
22237 
22238 }
22239 
22240 template<typename TSeq>
22242  Agent<TSeq> & other,
22243  size_t n_this,
22244  size_t n_other
22245 )
22246 {
22247 
22248  if (n_this >= n_neighbors)
22249  throw std::range_error(
22250  "The neighbor you want to swap is out of range. This Agent only has " +
22251  std::to_string(n_neighbors) + " neighbors."
22252  );
22253  if (n_other >= other.n_neighbors)
22254  throw std::range_error(
22255  "The neighbor you want to swap is out of range. This Agent only has " +
22256  std::to_string(other.n_neighbors) + " neighbors."
22257  );
22258 
22259  // Getting the agents
22260  auto & pop = model->population;
22261  auto & neigh_this = pop[(*neighbors)[n_this]];
22262  auto & neigh_other = pop[(*other.neighbors)[n_other]];
22263 
22264  // Getting the locations in the neighbors
22265  size_t loc_this_in_neigh = (*neighbors_locations)[n_this];
22266  size_t loc_other_in_neigh = (*other.neighbors_locations)[n_other];
22267 
22268  // Changing ids
22269  std::swap((*neighbors)[n_this], (*other.neighbors)[n_other]);
22270 
22271  if (!model->directed)
22272  {
22273  std::swap(
22274  (*neigh_this.neighbors)[loc_this_in_neigh],
22275  (*neigh_other.neighbors)[loc_other_in_neigh]
22276  );
22277 
22278  // Changing the locations
22279  std::swap((*neighbors_locations)[n_this], (*other.neighbors_locations)[n_other]);
22280 
22281  std::swap(
22282  (*neigh_this.neighbors_locations)[loc_this_in_neigh],
22283  (*neigh_other.neighbors_locations)[loc_other_in_neigh]
22284  );
22285  }
22286 
22287 }
22288 
22289 template<typename TSeq>
22290 inline std::vector< Agent<TSeq> *> Agent<TSeq>::get_neighbors()
22291 {
22292  std::vector< Agent<TSeq> * > res(n_neighbors, nullptr);
22293  for (size_t i = 0u; i < n_neighbors; ++i)
22294  res[i] = &model->population[(*neighbors)[i]];
22295 
22296  return res;
22297 }
22298 
22299 template<typename TSeq>
22300 inline size_t Agent<TSeq>::get_n_neighbors() const
22301 {
22302  return n_neighbors;
22303 }
22304 
22305 template<typename TSeq>
22306 inline void Agent<TSeq>::change_state(
22307  Model<TSeq> * model,
22308  epiworld_fast_uint new_state,
22309  epiworld_fast_int queue
22310  )
22311 {
22312 
22313  model->events_add(
22314  this, nullptr, nullptr, nullptr, new_state, queue,
22315  default_change_state<TSeq>, -1, -1
22316  );
22317 
22318  return;
22319 
22320 }
22321 
22322 template<typename TSeq>
22323 inline const unsigned int & Agent<TSeq>::get_state() const {
22324  return state;
22325 }
22326 
22327 template<typename TSeq>
22328 inline void Agent<TSeq>::reset()
22329 {
22330 
22331  this->virus = nullptr;
22332 
22333  this->tools.clear();
22334  n_tools = 0u;
22335 
22336  this->entities.clear();
22337  this->entities_locations.clear();
22338  this->n_entities = 0u;
22339 
22340  this->state = 0u;
22341  this->state_prev = 0u;
22342 
22343  this->state_last_changed = -1;
22344 
22345 }
22346 
22347 template<typename TSeq>
22348 inline bool Agent<TSeq>::has_tool(epiworld_fast_uint t) const
22349 {
22350 
22351  for (auto & tool : tools)
22352  if (tool->get_id() == static_cast<int>(t))
22353  return true;
22354 
22355  return false;
22356 
22357 }
22358 
22359 template<typename TSeq>
22360 inline bool Agent<TSeq>::has_tool(std::string name) const
22361 {
22362 
22363  for (auto & tool : tools)
22364  if (tool->get_name() == name)
22365  return true;
22366 
22367  return false;
22368 
22369 }
22370 
22371 template<typename TSeq>
22372 inline bool Agent<TSeq>::has_tool(const Tool<TSeq> & tool) const
22373 {
22374 
22375  return has_tool(tool.get_id());
22376 
22377 }
22378 
22379 template<typename TSeq>
22380 inline bool Agent<TSeq>::has_virus(epiworld_fast_uint t) const
22381 {
22382  if (virus->get_id() == static_cast<int>(t))
22383  return true;
22384 
22385  return false;
22386 }
22387 
22388 template<typename TSeq>
22389 inline bool Agent<TSeq>::has_virus(std::string name) const
22390 {
22391 
22392  if (virus->get_name() == name)
22393  return true;
22394 
22395  return false;
22396 
22397 }
22398 
22399 template<typename TSeq>
22400 inline bool Agent<TSeq>::has_virus(const Virus<TSeq> & virus) const
22401 {
22402 
22403  return has_virus(virus.get_id());
22404 
22405 }
22406 
22407 template<typename TSeq>
22408 inline bool Agent<TSeq>::has_entity(epiworld_fast_uint t) const
22409 {
22410 
22411  for (auto & entity : entities)
22412  if (entity == t)
22413  return true;
22414 
22415  return false;
22416 
22417 }
22418 
22419 template<typename TSeq>
22420 inline bool Agent<TSeq>::has_entity(std::string name) const
22421 {
22422 
22423  for (auto & entity : entities)
22424  if (model->get_entity(entity).get_name() == name)
22425  return true;
22426 
22427  return false;
22428 
22429 }
22430 
22431 template<typename TSeq>
22432 inline void Agent<TSeq>::print(
22433  bool compressed
22434  ) const
22435 {
22436 
22437  if (compressed)
22438  {
22439  printf_epiworld(
22440  "Agent: %i, state: %s (%i), Has virus: %s, NTools: %ii NNeigh: %i\n",
22441  static_cast<int>(id),
22442  model->states_labels[state].c_str(),
22443  static_cast<int>(state),
22444  virus == nullptr ? std::string("no").c_str() : std::string("yes").c_str(),
22445  static_cast<int>(n_tools),
22446  static_cast<int>(n_neighbors)
22447  );
22448  }
22449  else {
22450 
22451  printf_epiworld("Information about agent id %i\n",
22452  static_cast<int>(this->id));
22453  printf_epiworld(" State : %s (%i)\n",
22454  model->states_labels[state].c_str(), static_cast<int>(state));
22455  printf_epiworld(" Has virus : %s\n", virus == nullptr ?
22456  std::string("no").c_str() : std::string("yes").c_str());
22457  printf_epiworld(" Tool count : %i\n", static_cast<int>(n_tools));
22458  printf_epiworld(" Neigh. count : %i\n", static_cast<int>(n_neighbors));
22459 
22460  size_t nfeats = model->get_agents_data_ncols();
22461  if (nfeats > 0)
22462  {
22463 
22464  printf_epiworld(
22465  "This model includes features (%i): [ ",
22466  static_cast<int>(nfeats)
22467  );
22468 
22469  int max_to_show = static_cast<int>((nfeats > 10)? 10 : nfeats);
22470 
22471  for (int k = 0; k < max_to_show; ++k)
22472  {
22473  printf_epiworld("%.2f", this->operator[](k));
22474 
22475  if (k != (max_to_show - 1))
22476  {
22477  printf_epiworld(", ");
22478  } else {
22479  printf_epiworld(" ]\n");
22480  }
22481 
22482  }
22483 
22484  }
22485 
22486  }
22487 
22488  return;
22489 
22490 }
22491 
22492 template<typename TSeq>
22493 inline double & Agent<TSeq>::operator()(size_t j)
22494 {
22495 
22496  if (model->agents_data_ncols <= j)
22497  throw std::logic_error("The requested feature of the agent is out of range.");
22498 
22499  return *(model->agents_data + j * model->size() + id);
22500 
22501 }
22502 
22503 template<typename TSeq>
22504 inline double & Agent<TSeq>::operator[](size_t j)
22505 {
22506  return *(model->agents_data + j * model->size() + id);
22507 }
22508 
22509 template<typename TSeq>
22510 inline double Agent<TSeq>::operator()(size_t j) const
22511 {
22512 
22513  if (model->agents_data_ncols <= j)
22514  throw std::logic_error("The requested feature of the agent is out of range.");
22515 
22516  return *(model->agents_data + j * model->size() + id);
22517 
22518 }
22519 
22520 template<typename TSeq>
22521 inline double Agent<TSeq>::operator[](size_t j) const
22522 {
22523  return *(model->agents_data + j * model->size() + id);
22524 }
22525 
22526 template<typename TSeq>
22528 {
22529  return Entities<TSeq>(*this);
22530 }
22531 
22532 template<typename TSeq>
22534 {
22535  return Entities_const<TSeq>(*this);
22536 }
22537 
22538 template<typename TSeq>
22539 inline const Entity<TSeq> & Agent<TSeq>::get_entity(size_t i) const
22540 {
22541  if (n_entities == 0)
22542  throw std::range_error("Agent id " + std::to_string(id) + " has no entities.");
22543 
22544  if (i >= n_entities)
22545  throw std::range_error("Trying to get to an agent's entity outside of the range.");
22546 
22547  return model->get_entity(entities[i]);
22548 }
22549 
22550 template<typename TSeq>
22551 inline Entity<TSeq> & Agent<TSeq>::get_entity(size_t i)
22552 {
22553  if (n_entities == 0)
22554  throw std::range_error("Agent id " + std::to_string(id) + " has no entities.");
22555 
22556  if (i >= n_entities)
22557  throw std::range_error("Trying to get to an agent's entity outside of the range.");
22558 
22559  return model->get_entity(entities[i]);
22560 }
22561 
22562 template<typename TSeq>
22563 inline size_t Agent<TSeq>::get_n_entities() const
22564 {
22565  return n_entities;
22566 }
22567 
22568 template<typename TSeq>
22569 inline bool Agent<TSeq>::operator==(const Agent<TSeq> & other) const
22570 {
22571 
22572  EPI_DEBUG_FAIL_AT_TRUE(
22573  n_neighbors != other.n_neighbors,
22574  "Agent:: n_eighbors don't match"
22575  )
22576 
22577 
22578  for (size_t i = 0u; i < n_neighbors; ++i)
22579  {
22580  EPI_DEBUG_FAIL_AT_TRUE(
22581  (*neighbors)[i] != (*other.neighbors)[i],
22582  "Agent:: neighbor[i] don't match"
22583  )
22584  }
22585 
22586  EPI_DEBUG_FAIL_AT_TRUE(
22587  n_entities != other.n_entities,
22588  "Agent:: n_entities don't match"
22589  )
22590 
22591 
22592  for (size_t i = 0u; i < n_entities; ++i)
22593  {
22594  EPI_DEBUG_FAIL_AT_TRUE(
22595  entities[i] != other.entities[i],
22596  "Agent:: entities[i] don't match"
22597  )
22598  }
22599 
22600  EPI_DEBUG_FAIL_AT_TRUE(
22601  state != other.state,
22602  "Agent:: state don't match"
22603  )
22604 
22605 
22606  EPI_DEBUG_FAIL_AT_TRUE(
22607  state_prev != other.state_prev,
22608  "Agent:: state_prev don't match"
22609  )
22610 
22611 
22612  // EPI_DEBUG_FAIL_AT_TRUE(
22613  // state_last_changed != other.state_last_changed,
22614  // "Agent:: state_last_changed don't match"
22615  // ) ///< Last time the agent was updated.
22616 
22617  EPI_DEBUG_FAIL_AT_TRUE(
22618  ((virus == nullptr) && (other.virus != nullptr)) ||
22619  ((virus != nullptr) && (other.virus == nullptr)),
22620  "Agent:: virus don't match"
22621  )
22622 
22623  if ((virus != nullptr) && (other.virus != nullptr))
22624  {
22625  EPI_DEBUG_FAIL_AT_TRUE(
22626  *virus != *other.virus,
22627  "Agent:: virus doesn't match"
22628  )
22629  }
22630 
22631  EPI_DEBUG_FAIL_AT_TRUE(n_tools != other.n_tools, "Agent:: n_tools don't match")
22632 
22633  for (size_t i = 0u; i < n_tools; ++i)
22634  {
22635 
22636  EPI_DEBUG_FAIL_AT_TRUE(
22637  tools[i] != other.tools[i],
22638  "Agent:: tools[i] don't match"
22639  )
22640 
22641  }
22642 
22643  return true;
22644 
22645 }
22646 
22647 #endif
22648 /*//////////////////////////////////////////////////////////////////////////////
22650 
22651  End of -include/epiworld/agent-meat.hpp-
22652 
22655 
22656 
22657 
22658 /*//////////////////////////////////////////////////////////////////////////////
22660 
22661  Start of -include/epiworld/agentssample-bones.hpp-
22662 
22665 
22666 
22667 #ifndef EPIWORLD_AGENTS_BONES_HPP
22668 #define EPIWORLD_AGENTS_BONES_HPP
22669 
22670 class SAMPLETYPE {
22671 public:
22672  static const int MODEL = 0;
22673  static const int ENTITY = 1;
22674  static const int AGENT = 2;
22675 };
22676 
22677 // template<typename TSeq>
22678 // class Agent;
22679 
22680 // template<typename TSeq>
22681 // class Model;
22682 
22683 // template<typename TSeq>
22684 // class Entity;
22685 
22693 template<typename TSeq = EPI_DEFAULT_TSEQ>
22694 class AgentsSample {
22695 private:
22696 
22697  size_t sample_size = 0u;
22698 
22699  std::vector< Agent<TSeq>* >* agents = nullptr; ///< Pointer to sample of agents
22700  size_t * agents_n = nullptr; ///< Size of sample of agents
22701 
22702  std::vector< size_t >* agents_left = nullptr; ///< Pointer to agents left (iota)
22703  size_t * agents_left_n = nullptr; ///< Size of agents left
22704 
22705  Model<TSeq> * model = nullptr; ///< Extracts runif() and (if the case) population.
22706  Entity<TSeq> * entity = nullptr; ///
22707  Agent<TSeq> * agent = nullptr;
22708 
22709  int sample_type = SAMPLETYPE::AGENT;
22710  std::vector< size_t > states = {};
22711 
22712  void sample_n(size_t n); ///< Backbone function for sampling
22713 
22714 
22715 public:
22716 
22717  // Not available (for now)
22718  AgentsSample() = delete; ///< Default constructor
22719  AgentsSample(const AgentsSample<TSeq> & a) = delete; ///< Copy constructor
22720  AgentsSample(AgentsSample<TSeq> && a) = delete; ///< Move constructor
22721 
22722  AgentsSample(
22723  Model<TSeq> & model_, size_t n,
22724  std::vector< size_t > states_ = {},
22725  bool truncate = false
22726  );
22727 
22728  AgentsSample(
22729  Model<TSeq> * model,
22730  Entity<TSeq> & entity_,
22731  size_t n,
22732  std::vector< size_t > states_ = {},
22733  bool truncate = false
22734  );
22735 
22736  AgentsSample(
22737  Model<TSeq> * model,
22738  Agent<TSeq> & agent_,
22739  size_t n,
22740  std::vector< size_t > states_ = {},
22741  bool truncate = false
22742  );
22743 
22744  ~AgentsSample();
22745 
22746  typename std::vector< Agent<TSeq> * >::iterator begin();
22747  typename std::vector< Agent<TSeq> * >::iterator end();
22748 
22749  Agent<TSeq> * operator[](size_t n);
22750  Agent<TSeq> * operator()(size_t n);
22751  size_t size() const noexcept;
22752 
22753 };
22754 
22755 template<typename TSeq>
22756 inline AgentsSample<TSeq>::AgentsSample(
22757  Model<TSeq> & model_,
22758  size_t n,
22759  std::vector< size_t > states_,
22760  bool truncate
22761  ) {
22762 
22763  states = states_;
22764 
22765  if (truncate)
22766  {
22767 
22768  if (n > model_.size())
22769  n = model_.size();
22770 
22771  } else if (n > model_.size())
22772  throw std::logic_error(
22773  "There are only " + std::to_string(model_.size()) + " agents. You cannot " +
22774  "sample " + std::to_string(n));
22775 
22776  sample_size = n;
22777  model = &model_;
22778  sample_type = SAMPLETYPE::MODEL;
22779 
22780  agents = &model_.sampled_population;
22781  agents_n = &model_.sampled_population_n;
22782 
22783  agents_left = &model_.population_left;
22784  agents_left_n = &model_.population_left_n;
22785 
22786  sample_n(n);
22787 
22788  return;
22789 
22790 }
22791 
22792 template<typename TSeq>
22793 inline AgentsSample<TSeq>::AgentsSample(
22794  Model<TSeq> * model,
22795  Entity<TSeq> & entity_,
22796  size_t n,
22797  std::vector< size_t > states_,
22798  bool truncate
22799  ) {
22800 
22801  states = states_;
22802 
22803  if (truncate)
22804  {
22805 
22806  if (n > entity_.size())
22807  n = entity_.size();
22808 
22809  } else if (n > entity_.size())
22810  throw std::logic_error(
22811  "There are only " + std::to_string(entity_.size()) + " agents. You cannot " +
22812  "sample " + std::to_string(n));
22813 
22814  sample_size = n;
22815  model = &entity_.model;
22816  sample_type = SAMPLETYPE::ENTITY;
22817 
22818  agents = &entity_.sampled_agents;
22819  agents_n = &entity_.sampled_agents_n;
22820 
22821  agents_left = &entity_.sampled_agents_left;
22822  agents_left_n = &entity_.sampled_agents_left_n;
22823 
22824  sample_n(n);
22825 
22826  return;
22827 
22828 }
22829 
22842 template<typename TSeq>
22843 inline AgentsSample<TSeq>::AgentsSample(
22844  Model<TSeq> * model,
22845  Agent<TSeq> & agent_,
22846  size_t n,
22847  std::vector< size_t > states_,
22848  bool truncate
22849  )
22850 {
22851 
22852  states = states_;
22853  sample_type = SAMPLETYPE::AGENT;
22854 
22855  agent = &agent_;
22856 
22857  agents = &agent_.sampled_agents;
22858  agents_n = &agent_.sampled_agents_n;
22859 
22860  // Computing the cumulative sum of counts across entities
22861  size_t agents_in_entities = 0;
22862  Entities<TSeq> entities_a = agent->get_entities();
22863 
22864  std::vector< size_t > cum_agents_count(entities_a.size(), 0);
22865  int idx = -1;
22866  for (auto & e : entities_a)
22867  {
22868  if (++idx == 0)
22869  cum_agents_count[idx] = (e->size() - 1u);
22870  else
22871  cum_agents_count[idx] = (
22872  (e->size() - 1u) +
22873  cum_agents_count[idx - 1]
22874  );
22875 
22876  agents_in_entities += (e->size() - 1u);
22877  }
22878 
22879  if (truncate)
22880  {
22881 
22882  if (n > agents_in_entities)
22883  n = agents_in_entities;
22884 
22885  } else if (n > agents_in_entities)
22886  throw std::logic_error(
22887  "There are only " + std::to_string(agents_in_entities) +
22888  " agents. You cannot " +
22889  "sample " + std::to_string(n)
22890  );
22891 
22892  sample_size = n;
22893 
22894  if (agents->size() < n)
22895  agents->resize(n);
22896 
22897  size_t i_obs = 0u;
22898  for (size_t i = 0u; i < sample_size; ++i)
22899  {
22900 
22901  // Sampling a single agent from the set of entities
22902  int jth = std::floor(model->runif() * agents_in_entities);
22903  for (size_t e = 0u; e < cum_agents_count.size(); ++e)
22904  {
22905 
22906  // Are we in the limit?
22907  if (jth <= cum_agents_count[e])
22908  {
22909  size_t agent_idx = 0u;
22910  if (e == 0) // From the first group
22911  agent_idx = entities_a[e][jth]->get_id();
22912  else
22913  agent_idx = entities_a[e][jth - cum_agents_count[e - 1]]->get_id();
22914 
22915 
22916  // Checking if states was specified
22917  if (states.size())
22918  {
22919 
22920  // Getting the state
22921  size_t state = model->population[agent_idx].get_state();
22922 
22923  if (std::find(states.begin(), states.end(), state) != states.end())
22924  continue;
22925 
22926  }
22927 
22928  agents->operator[](i_obs++) = &(model->population[agent_idx]);
22929 
22930  break;
22931  }
22932 
22933  }
22934  }
22935 
22936  return;
22937 
22938 }
22939 
22940 template<typename TSeq>
22941 inline AgentsSample<TSeq>::~AgentsSample() {}
22942 
22943 template<typename TSeq>
22944 inline size_t AgentsSample<TSeq>::size() const noexcept
22945 {
22946  return this->sample_size;
22947 }
22948 
22949 template<typename TSeq>
22950 inline Agent<TSeq> * AgentsSample<TSeq>::operator[](size_t i)
22951 {
22952 
22953  return agents->operator[](i);
22954 
22955 }
22956 
22957 template<typename TSeq>
22958 inline Agent<TSeq> * AgentsSample<TSeq>::operator()(size_t i)
22959 {
22960 
22961  if (i >= this->sample_size)
22962  throw std::range_error("The requested agent is out of range.");
22963 
22964  return agents->operator[](i);
22965 
22966 }
22967 
22968 template<typename TSeq>
22969 inline typename std::vector< Agent<TSeq> * >::iterator AgentsSample<TSeq>::begin()
22970 {
22971  // Check for null pointer
22972  if (agents == nullptr)
22973  return typename std::vector< Agent<TSeq> * >::iterator{};
22974 
22975  return agents->begin();
22976 }
22977 
22978 template<typename TSeq>
22979 inline typename std::vector< Agent<TSeq> * >::iterator AgentsSample<TSeq>::end()
22980 {
22981  // Check for null pointer
22982  if (agents == nullptr)
22983  return typename std::vector< Agent<TSeq> * >::iterator{};
22984 
22985  // Ensure we don't go beyond the actual vector size
22986  size_t actual_end = std::min(sample_size, agents->size());
22987  return agents->begin() + actual_end;
22988 }
22989 
22990 template<typename TSeq>
22991 inline void AgentsSample<TSeq>::sample_n(size_t n)
22992 {
22993 
22994  // Reducing size
22995  if (states.size())
22996  {
22997 
22998  // Getting the number of agents left
22999  agents_left->clear();
23000 
23001  if (sample_type == SAMPLETYPE::MODEL)
23002  {
23003 
23004  // Making some room
23005  agents_left->reserve(model->size());
23006 
23007  // Iterating through the agents in the population
23008  for (size_t a_i = 0u; a_i < model->population.size(); ++a_i)
23009  {
23010 
23011  // If the agent is within the selected set of states,
23012  // then we add it to the list of agents left
23013  size_t s = model->population[a_i].get_state();
23014  if (std::find(states.begin(), states.end(), s) != states.end())
23015  agents_left->push_back(a_i);
23016 
23017  }
23018 
23019  }
23020  else if (sample_type == SAMPLETYPE::ENTITY)
23021  {
23022 
23023  // Making room
23024  agents_left->reserve(entity->size());
23025 
23026  // Iterating through the agents in the entity
23027  for (size_t a_i = 0u; a_i < entity->size(); ++a_i)
23028  {
23029  size_t s = model->population[entity->agents[a_i]].get_state();
23030  if (std::find(states.begin(), states.end(), s) != states.end())
23031  agents_left->push_back(a_i);
23032 
23033  }
23034 
23035  }
23036 
23037  } else {
23038 
23039  // Checking if the size of the entity has changed (or hasn't been initialized)
23040  if (sample_type == SAMPLETYPE::MODEL)
23041  {
23042 
23043  if (model->size() != agents_left->size())
23044  {
23045  agents_left->resize(model->size(), 0u);
23046  std::iota(agents_left->begin(), agents_left->end(), 0u);
23047  }
23048 
23049  } else if (sample_type == SAMPLETYPE::ENTITY) {
23050 
23051  if (entity->size() != agents_left->size())
23052  {
23053 
23054  agents_left->resize(entity->size(), 0u);
23055  std::iota(agents_left->begin(), agents_left->end(), 0u);
23056 
23057  }
23058 
23059  }
23060 
23061  }
23062 
23063  // Restart the counter of agents left
23064  *agents_left_n = agents_left->size();
23065 
23066  // Making sure we have enough room for the sample of agents
23067  if (agents->size() < sample_size)
23068  agents->resize(sample_size, nullptr);
23069 
23070  if (sample_type == SAMPLETYPE::MODEL)
23071  {
23072 
23073  #ifdef EPI_DEBUG
23074  std::vector< bool > __sampled(model->size(), true);
23075  for (auto & a_i: *agents_left)
23076  __sampled[a_i] = false;
23077  #endif
23078 
23079  for (size_t i = 0u; i < n; ++i)
23080  {
23081 
23082  // Sampling from 0 to (agents_left_n - 1)
23083  size_t ith_ = static_cast<size_t>(model->runif() * ((*agents_left_n)--));
23084 
23085  // Getting the id of the agent and adding it to the list of agents
23086  size_t ith = agents_left->operator[](ith_);
23087  agents->operator[](i) = &model->population[ith];
23088 
23089  #ifdef EPI_DEBUG
23090  if (__sampled[ith])
23091  throw std::logic_error("The same agent was sampled twice.");
23092  else
23093  __sampled[ith] = true;
23094  #endif
23095 
23096  // Updating list
23097  std::swap(
23098  agents_left->operator[](ith_),
23099  agents_left->operator[](*agents_left_n)
23100  );
23101 
23102  }
23103 
23104 
23105  }
23106  else if (sample_type == SAMPLETYPE::ENTITY)
23107  {
23108 
23109  #ifdef EPI_DEBUG
23110  std::vector< bool > __sampled(entity->size(), true);
23111  for (auto & a_i: *agents_left)
23112  __sampled[a_i] = false;
23113  #endif
23114 
23115  for (size_t i = 0u; i < n; ++i)
23116  {
23117 
23118  size_t ith_ = static_cast<size_t>(model->runif() * ((*agents_left_n)--));
23119  size_t ith = agents_left->operator[](ith_);
23120  agents->operator[](i) = &model->population[entity->agents[ith]];
23121 
23122  #ifdef EPI_DEBUG
23123  if (__sampled[ith])
23124  throw std::logic_error("The same agent was sampled twice.");
23125  else
23126  __sampled[ith] = true;
23127  #endif
23128 
23129  // Updating list
23130  std::swap(agents_left->operator[](ith_), agents_left->operator[](*agents_left_n));
23131 
23132  }
23133 
23134  }
23135 
23136  return;
23137 
23138 }
23139 
23140 #endif
23141 /*//////////////////////////////////////////////////////////////////////////////
23143 
23144  End of -include/epiworld/agentssample-bones.hpp-
23145 
23148 
23149 
23150 
23151 /*//////////////////////////////////////////////////////////////////////////////
23153 
23154  Start of -include/epiworld/contacttracing-bones.hpp-
23155 
23158 
23159 
23160 #ifndef EPIWORLD_CONTACT_TRACING_H
23161 #define EPIWORLD_CONTACT_TRACING_H
23162 
23175 class ContactTracing
23176 {
23177 private:
23178 
23179  std::vector< size_t > contact_matrix;
23180  std::vector< size_t > contacts_per_agent;
23181  std::vector< size_t > contact_date;
23182 
23183  size_t n_agents;
23184  size_t max_contacts;
23185 
23186  size_t get_location(size_t row, size_t col) const;
23187 
23188 public:
23189 
23190  ContactTracing();
23191 
23198  ContactTracing(size_t n_agents, size_t max_contacts);
23199 
23207  void add_contact(size_t agent_a, size_t agent_b, size_t day);
23208 
23215  size_t get_n_contacts(size_t agent);
23216 
23225  std::pair<size_t, size_t> get_contact(size_t agent, size_t idx);
23226 
23235  void reset(
23236  size_t n_agents,
23237  size_t max_contacts
23238  );
23239 
23245  void print(size_t agent);
23246 };
23247 
23248 inline size_t ContactTracing::get_location(size_t row, size_t col) const
23249 {
23250  return col * n_agents + row;
23251 }
23252 
23253 inline ContactTracing::ContactTracing()
23254 {
23255  n_agents = 0u;
23256  max_contacts = 0u;
23257 }
23258 
23259 inline ContactTracing::ContactTracing(size_t n_agents, size_t max_contacts)
23260 {
23261  this->n_agents = n_agents;
23262  this->max_contacts = max_contacts;
23263 
23264  contact_matrix.resize(n_agents * max_contacts, 0u);
23265  contacts_per_agent.resize(n_agents, 0);
23266  contact_date.resize(n_agents * max_contacts, 0);
23267 }
23268 
23269 inline void ContactTracing::add_contact(size_t agent_a, size_t agent_b, size_t day)
23270 {
23271 
23272  // Checking overflow
23273  size_t col_location = contacts_per_agent[agent_a] % max_contacts;
23274  size_t array_location = get_location(agent_a, col_location);
23275 
23276  contact_matrix[array_location] = agent_b;
23277  contact_date[array_location] = day;
23278 
23279  contacts_per_agent[agent_a] += 1;
23280 
23281 }
23282 
23283 inline size_t ContactTracing::get_n_contacts(size_t agent)
23284 {
23285  return contacts_per_agent[agent];
23286 }
23287 
23288 inline std::pair< size_t, size_t> ContactTracing::get_contact(size_t agent, size_t idx)
23289 {
23290  if (
23291  (idx >= contacts_per_agent[agent]) ||
23292  (idx >= max_contacts)
23293  )
23294  throw std::out_of_range("Index out of range in get_contact");
23295 
23296  size_t col_location = idx % max_contacts;
23297  size_t array_location = get_location(agent, col_location);
23298 
23299  return { contact_matrix[array_location], contact_date[array_location] };
23300 }
23301 
23302 inline void ContactTracing::reset(size_t n_agents, size_t max_contacts)
23303 {
23304 
23305  this->n_agents = n_agents;
23306  this->max_contacts = max_contacts;
23307 
23308  contact_matrix.assign(n_agents * max_contacts, 0u);
23309  contacts_per_agent.assign(n_agents, 0u);
23310  contact_date.assign(n_agents * max_contacts, 0u);
23311 }
23312 
23313 inline void ContactTracing::print(size_t agent)
23314 {
23315 
23316  size_t n_contacts = contacts_per_agent[agent];
23317  if (n_contacts > max_contacts)
23318  n_contacts = max_contacts;
23319 
23320  printf_epiworld("Agent %zu has %zu contacts: ", agent, n_contacts);
23321  for (size_t i = 0u; i < n_contacts; ++i)
23322  {
23323  auto [contact_id, contact_day] = get_contact(agent, i);
23324  printf_epiworld("(%zu, day %zu) ", contact_id, contact_day);
23325  }
23326  printf_epiworld("\n");
23327 
23328  return;
23329 
23330 }
23331 
23332 #endif
23333 /*//////////////////////////////////////////////////////////////////////////////
23335 
23336  End of -include/epiworld/contacttracing-bones.hpp-
23337 
23340 
23341 
23342 /*//////////////////////////////////////////////////////////////////////////////
23344 
23345  Start of -include/epiworld/models/models.hpp-
23346 
23349 
23350 
23351 #ifndef EPIWORLD_MODELS_HPP
23352 #define EPIWORLD_MODELS_HPP
23353 
23354 namespace epimodels {
23355 
23356 /*//////////////////////////////////////////////////////////////////////////////
23358 
23359  Start of -include/epiworld/models/init-functions.hpp-
23360 
23363 
23364 
23365 #ifndef EPIWORLD_MODELS_INIT_FUNCTIONS_HPP
23366 #define EPIWORLD_MODELS_INIT_FUNCTIONS_HPP
23367 
23372 template<typename TSeq>
23373 inline std::function<void(Model<TSeq>*)> create_init_function_sir(
23374  std::vector< double > proportions_
23375 ) {
23376 
23377  // Checking widths
23378  if (proportions_.size() != 1u)
23379  throw std::invalid_argument(
23380  "The vector of proportions must have a single element."
23381  );
23382 
23383  // Proportion should be within [0, 1]
23384  if ((proportions_[0] < 0.0) || (proportions_[0] > 1.0))
23385  throw std::invalid_argument(
23386  "The proportion must be within (0, 1)."
23387  );
23388 
23389  double prop = proportions_[0u];
23390 
23391  std::function<void(Model<TSeq>*)> fun =
23392  [prop] (Model<TSeq> * model) -> void {
23393 
23394  // Figuring out information about the viruses
23395  double tot = 0.0;
23396  double n = static_cast<double>(model->size());
23397  for (const auto & agent: model->get_agents())
23398  {
23399  if (agent.get_virus() != nullptr)
23400  tot += 1.0;
23401  }
23402  tot /= n;
23403 
23404  // Putting the total into context
23405  double tot_left = 1.0 - tot;
23406 
23407  // Since susceptible and infected are "fixed,"
23408  // we only need to change recovered
23409  size_t nrecovered = prop * tot_left * n;
23410 
23411  AgentsSample<TSeq> sample(
23412  *model,
23413  nrecovered,
23414  {0u},
23415  true
23416  );
23417 
23418  // Setting up the initial states
23419  for (auto & agent : sample)
23420  agent->change_state(model, 2, Queue<TSeq>::NoOne);
23421 
23422  // Running the events
23423  model->events_run();
23424 
23425  return;
23426 
23427  };
23428 
23429  return fun;
23430 
23431 }
23432 
23437 template<typename TSeq>
23438 inline std::function<void(Model<TSeq>*)> create_init_function_sird(
23439  std::vector< double > prop
23440 ) {
23441 
23442  // Check length of prop equals two
23443  if (prop.size() != 2u)
23444  throw std::invalid_argument(
23445  "The vector of proportions must have two elements."
23446  );
23447 
23448  // Check elements in prop are within [0, 1] and sum up to 1
23449  double tot = 0.0;
23450  for (auto & v : prop)
23451  {
23452  if ((v < 0.0) || (v > 1.0))
23453  throw std::invalid_argument(
23454  "The proportion must be within (0, 1)."
23455  );
23456  tot += v;
23457  }
23458 
23459  if (tot >= 1.0)
23460  throw std::invalid_argument(
23461  "The proportions must sum up to 1."
23462  );
23463 
23464  std::function<void(Model<TSeq>*)> fun =
23465  [prop] (Model<TSeq> * model) -> void {
23466 
23467  // Figuring out information about the viruses
23468  double tot = 0.0;
23469  double n = static_cast<double>(model->size());
23470  for (const auto & agent: model->get_agents())
23471  {
23472  if (agent.get_virus() != nullptr)
23473  tot += 1.0;
23474  }
23475  tot /= n;
23476 
23477  // Putting the total into context
23478  double tot_left = 1.0 - tot;
23479 
23480  // Since susceptible and infected are "fixed,"
23481  // we only need to change recovered
23482  size_t nrecovered = prop[0u] * tot_left * n;
23483  size_t ndeceased = prop[01] * tot_left * n;
23484 
23485  AgentsSample<TSeq> sample_recover(
23486  *model,
23487  nrecovered,
23488  {0u},
23489  true
23490  );
23491 
23492  // Setting up the initial states
23493  for (auto & agent : sample_recover)
23494  agent->change_state(model, 2, Queue<TSeq>::NoOne);
23495 
23496  AgentsSample<TSeq> sample_deceased(
23497  *model,
23498  ndeceased,
23499  {0u},
23500  true
23501  );
23502 
23503  // Setting up the initial states
23504  for (auto & agent : sample_deceased)
23505  agent->change_state(model, 3, Queue<TSeq>::NoOne);
23506 
23507  // Running the events
23508  model->events_run();
23509 
23510  return;
23511 
23512  };
23513 
23514  return fun;
23515 
23516 }
23517 
23518 
23523 template<typename TSeq>
23524 inline std::function<void(Model<TSeq>*)> create_init_function_seir(
23525  std::vector< double > proportions_
23526 ) {
23527 
23528  // Checking widths
23529  if (proportions_.size() != 2u) {
23530  throw std::invalid_argument("-proportions_- must have two entries.");
23531  }
23532 
23533  // proportions_ are values between 0 and 1, otherwise error
23534  for (auto & v : proportions_)
23535  if ((v < 0.0) || (v > 1.0))
23536  throw std::invalid_argument(
23537  "-proportions_- must have values between 0 and 1."
23538  );
23539 
23540 
23541  std::function<void(Model<TSeq>*)> fun =
23542  [proportions_] (Model<TSeq> * model) -> void {
23543 
23544  // Figuring out information about the viruses
23545  double tot = 0.0;
23546  double n = static_cast<double>(model->size());
23547  for (const auto & agent: model->get_agents())
23548  {
23549  if (agent.get_virus() != nullptr)
23550  tot += 1.0;
23551  }
23552  tot /= n;
23553 
23554  // Putting the total into context
23555  double tot_left = 1.0 - tot;
23556 
23557  // Since susceptible and infected are "fixed,"
23558  // we only need to change recovered
23559  size_t nexposed = proportions_[0u] * tot * n;
23560  size_t nrecovered = proportions_[1u] * tot_left * n;
23561 
23562  AgentsSample<TSeq> sample_suscept(
23563  *model,
23564  nrecovered,
23565  {0u},
23566  true
23567  );
23568 
23569  // Setting up the initial states
23570  for (auto & agent : sample_suscept)
23571  agent->change_state(model, 3, Queue<TSeq>::NoOne);
23572 
23573  AgentsSample<TSeq> sample_exposed(
23574  *model,
23575  nexposed,
23576  {1u},
23577  true
23578  );
23579 
23580  // Setting up the initial states
23581  for (auto & agent : sample_exposed)
23582  agent->change_state(model, 2, Queue<TSeq>::NoOne);
23583 
23584  // Running the events
23585  model->events_run();
23586 
23587  return;
23588 
23589  };
23590 
23591  return fun;
23592 
23593 }
23594 
23599 template<typename TSeq>
23600 inline std::function<void(Model<TSeq>*)> create_init_function_seird(
23601  std::vector< double > proportions_
23602 ) {
23603 
23604  // Checking widths
23605  if (proportions_.size() != 3u) {
23606  throw std::invalid_argument("-proportions_- must have three entries.");
23607  }
23608 
23609  // proportions_ are values between 0 and 1, otherwise error
23610  for (auto & v : proportions_)
23611  if ((v < 0.0) || (v > 1.0))
23612  throw std::invalid_argument(
23613  "-proportions_- must have values between 0 and 1."
23614  );
23615 
23616  // Last first two terms shouldn't add up to more than 1
23617  if ((proportions_[1u] + proportions_[2u]) > 1.0)
23618  throw std::invalid_argument(
23619  "The last two terms of -proportions_- must add up to less than 1."
23620  );
23621 
23622  std::function<void(Model<TSeq>*)> fun =
23623  [proportions_] (Model<TSeq> * model) -> void {
23624 
23625  // Figuring out information about the viruses
23626  double tot = 0.0;
23627  double n = static_cast<double>(model->size());
23628 
23629  for (const auto & agent: model->get_agents())
23630  {
23631  if (agent.get_virus() != nullptr)
23632  tot += 1.0;
23633  }
23634  tot /= n;
23635 
23636  // Putting the total into context
23637  double tot_left = 1.0 - tot;
23638 
23639  // Since susceptible and infected are "fixed,"
23640  // we only need to change recovered
23641  size_t nexposed = proportions_[0u] * tot * n;
23642  size_t nrecovered = proportions_[1u] * tot_left * n;
23643  size_t ndeceased = proportions_[2u] * tot_left * n;
23644 
23645  AgentsSample<TSeq> sample_suscept(
23646  *model,
23647  nrecovered,
23648  {0u},
23649  true
23650  );
23651 
23652  // Setting up the initial states
23653  for (auto & agent : sample_suscept)
23654  agent->change_state(model, 3, Queue<TSeq>::NoOne);
23655 
23656  AgentsSample<TSeq> sample_exposed(
23657  *model,
23658  nexposed,
23659  {1u},
23660  true
23661  );
23662 
23663  // Setting up the initial states
23664  for (auto & agent : sample_exposed)
23665  agent->change_state(model, 2, Queue<TSeq>::NoOne);
23666 
23667  // Running the events
23668  model->events_run();
23669 
23670  // Setting the initial states for the deceased
23671  AgentsSample<TSeq> sample_deceased(
23672  *model,
23673  ndeceased,
23674  {0u},
23675  true
23676  );
23677 
23678  // Setting up the initial states
23679  for (auto & agent : sample_deceased)
23680  agent->change_state(model, 4, Queue<TSeq>::NoOne);
23681 
23682  // Running the events
23683  model->events_run();
23684 
23685  return;
23686 
23687  };
23688 
23689  return fun;
23690 
23691 }
23692 
23693 
23694 #endif
23695 /*//////////////////////////////////////////////////////////////////////////////
23697 
23698  End of -include/epiworld/models/init-functions.hpp-
23699 
23702 
23703 
23704 
23705 /*//////////////////////////////////////////////////////////////////////////////
23707 
23708  Start of -include/epiworld/models/globalevents.hpp-
23709 
23712 
23713 
23714 #ifndef EPIWORLD_GLOBALEVENTS_HPP
23715 #define EPIWORLD_GLOBALEVENTS_HPP
23716 
23717 // This function creates a global action that distributes a tool
23718 // to agents with probability p.
23727 template<typename TSeq>
23728 inline std::function<void(Model<TSeq>*)> globalevent_tool(
23729  Tool<TSeq> & tool,
23730  double p
23731 ) {
23732 
23733  std::function<void(Model<TSeq>*)> fun = [p,&tool](
23734  Model<TSeq> * model
23735  ) -> void {
23736 
23737  for (auto & agent : model->get_agents())
23738  {
23739 
23740  // Check if the agent has the tool
23741  if (agent.has_tool(tool))
23742  continue;
23743 
23744  // Adding the tool
23745  if (model->runif() < p)
23746  agent.add_tool(tool, model);
23747 
23748 
23749  }
23750 
23751  #ifdef EPIWORLD_DEBUG
23752  tool.print();
23753  #endif
23754 
23755  return;
23756 
23757 
23758  };
23759 
23760  return fun;
23761 
23762 }
23763 
23764 // Same function as above, but p is now a function of a vector of coefficients
23765 // and a vector of variables.
23776 template<typename TSeq>
23777 inline std::function<void(Model<TSeq>*)> globalevent_tool_logit(
23778  Tool<TSeq> & tool,
23779  std::vector< size_t > vars,
23780  std::vector< double > coefs
23781 ) {
23782 
23783  std::function<void(Model<TSeq>*)> fun = [coefs,vars,&tool](
23784  Model<TSeq> * model
23785  ) -> void {
23786 
23787  for (auto & agent : model->get_agents())
23788  {
23789 
23790  // Check if the agent has the tool
23791  if (agent.has_tool(tool))
23792  continue;
23793 
23794  // Computing the probability using a logit. Uses OpenMP reduction
23795  // to sum the coefficients.
23796  double p = 0.0;
23797  #if defined(__OPENMP) || defined(_OPENMP)
23798  #pragma omp parallel for reduction(+:p)
23799  #endif
23800  for (size_t i = 0u; i < coefs.size(); ++i)
23801  p += coefs.at(i) * agent(vars[i]);
23802 
23803  p = 1.0 / (1.0 + std::exp(-p));
23804 
23805  // Adding the tool
23806  if (model->runif() < p)
23807  agent.add_tool(tool, model);
23808 
23809 
23810  }
23811 
23812  #ifdef EPIWORLD_DEBUG
23813  tool.print();
23814  #endif
23815 
23816  return;
23817 
23818 
23819  };
23820 
23821  return fun;
23822 
23823 }
23824 
23825 // A global action that updates a parameter in the model.
23834 template<typename TSeq>
23835 inline std::function<void(Model<TSeq>*)> globalevent_set_param(
23836  std::string param,
23837  double value
23838 ) {
23839 
23840  std::function<void(Model<TSeq>*)> fun = [value,param](
23841  Model<TSeq> * model
23842  ) -> void {
23843 
23844  model->set_param(param, value);
23845 
23846  return;
23847 
23848 
23849  };
23850 
23851  return fun;
23852 
23853 }
23854 #endif
23855 /*//////////////////////////////////////////////////////////////////////////////
23857 
23858  End of -include/epiworld/models/globalevents.hpp-
23859 
23862 
23863 
23864 /*//////////////////////////////////////////////////////////////////////////////
23866 
23867  Start of -include/epiworld/models/sis.hpp-
23868 
23871 
23872 
23873 #ifndef EPIWORLD_MODELS_SIS_HPP
23874 #define EPIWORLD_MODELS_SIS_HPP
23875 
23884 template<typename TSeq = EPI_DEFAULT_TSEQ>
23885 class ModelSIS : public epiworld::Model<TSeq>
23886 {
23887 
23888 public:
23889 
23890  static const int SUSCEPTIBLE = 0;
23891  static const int INFECTED = 1;
23892 
23893  ModelSIS() {};
23894 
23895  ModelSIS(
23896  ModelSIS<TSeq> & model,
23897  const std::string & vname,
23898  epiworld_double prevalence,
23899  epiworld_double transmission_rate,
23900  epiworld_double recovery_rate
23901  );
23902 
23903  ModelSIS(
23904  const std::string & vname,
23905  epiworld_double prevalence,
23906  epiworld_double transmission_rate,
23907  epiworld_double recovery_rate
23908  );
23909 
23910 };
23911 
23912 template<typename TSeq>
23913 inline ModelSIS<TSeq>::ModelSIS(
23914  ModelSIS<TSeq> & model,
23915  const std::string & vname,
23916  epiworld_double prevalence,
23917  epiworld_double transmission_rate,
23918  epiworld_double recovery_rate
23919  )
23920 {
23921 
23922  model.set_name("Susceptible-Infected-Susceptible (SIS)");
23923 
23924  // Adding statuses
23925  model.add_state("Susceptible", epiworld::default_update_susceptible<TSeq>);
23926  model.add_state("Infected", epiworld::default_update_exposed<TSeq>);
23927 
23928  // Setting up parameters
23929  model.add_param(transmission_rate, "Transmission rate");
23930  model.add_param(recovery_rate, "Recovery rate");
23931 
23932  // Preparing the virus -------------------------------------------
23933  epiworld::Virus<TSeq> virus(vname, prevalence, true);
23934  virus.set_state(ModelSIS<TSeq>::INFECTED, ModelSIS<TSeq>::SUSCEPTIBLE, ModelSIS<TSeq>::SUSCEPTIBLE);
23935 
23936  virus.set_prob_infecting(&model("Transmission rate"));
23937  virus.set_prob_recovery(&model("Recovery rate"));
23938  virus.set_prob_death(0.0);
23939 
23940  model.add_virus(virus);
23941 
23942  return;
23943 
23944 }
23945 
23946 template<typename TSeq>
23947 inline ModelSIS<TSeq>::ModelSIS(
23948  const std::string & vname,
23949  epiworld_double prevalence,
23950  epiworld_double transmission_rate,
23951  epiworld_double recovery_rate
23952  )
23953 {
23954 
23955  ModelSIS<TSeq>(
23956  *this,
23957  vname,
23958  prevalence,
23959  transmission_rate,
23960  recovery_rate
23961  );
23962 
23963  return;
23964 
23965 }
23966 
23967 #endif
23968 /*//////////////////////////////////////////////////////////////////////////////
23970 
23971  End of -include/epiworld/models/sis.hpp-
23972 
23975 
23976 
23977 /*//////////////////////////////////////////////////////////////////////////////
23979 
23980  Start of -include/epiworld/models/sir.hpp-
23981 
23984 
23985 
23986 #ifndef EPIWORLD_SIR_H
23987 #define EPIWORLD_SIR_H
23988 
23998 template<typename TSeq = EPI_DEFAULT_TSEQ>
23999 class ModelSIR : public epiworld::Model<TSeq>
24000 {
24001 public:
24002 
24003  ModelSIR() {};
24004 
24005  ModelSIR(
24006  ModelSIR<TSeq> & model,
24007  const std::string & vname,
24008  epiworld_double prevalence,
24009  epiworld_double transmission_rate,
24010  epiworld_double recovery_rate
24011  );
24012 
24013  ModelSIR(
24014  const std::string & vname,
24015  epiworld_double prevalence,
24016  epiworld_double transmission_rate,
24017  epiworld_double recovery_rate
24018  );
24019 
24025  ModelSIR<TSeq> & initial_states(
24026  std::vector< double > proportions_,
24027  std::vector< int > queue_ = {}
24028  );
24029 
24030 };
24031 
24032 template<typename TSeq>
24033 inline ModelSIR<TSeq>::ModelSIR(
24034  ModelSIR<TSeq> & model,
24035  const std::string & vname,
24036  epiworld_double prevalence,
24037  epiworld_double transmission_rate,
24038  epiworld_double recovery_rate
24039  )
24040 {
24041 
24042  // Adding statuses
24043  model.add_state("Susceptible", epiworld::default_update_susceptible<TSeq>);
24044  model.add_state("Infected", epiworld::default_update_exposed<TSeq>);
24045  model.add_state("Recovered");
24046 
24047  // Setting up parameters
24048  model.add_param(recovery_rate, "Recovery rate");
24049  model.add_param(transmission_rate, "Transmission rate");
24050 
24051  // Preparing the virus -------------------------------------------
24052  epiworld::Virus<TSeq> virus(vname, prevalence, true);
24053  virus.set_state(1,2,2);
24054 
24055  virus.set_prob_recovery(&model("Recovery rate"));
24056  virus.set_prob_infecting(&model("Transmission rate"));
24057 
24058  model.add_virus(virus);
24059 
24060  model.set_name("Susceptible-Infected-Recovered (SIR)");
24061 
24062  return;
24063 
24064 }
24065 
24066 template<typename TSeq>
24067 inline ModelSIR<TSeq>::ModelSIR(
24068  const std::string & vname,
24069  epiworld_double prevalence,
24070  epiworld_double transmission_rate,
24071  epiworld_double recovery_rate
24072  )
24073 {
24074 
24075  ModelSIR<TSeq>(
24076  *this,
24077  vname,
24078  prevalence,
24079  transmission_rate,
24080  recovery_rate
24081  );
24082 
24083  return;
24084 
24085 }
24086 
24087 template<typename TSeq>
24088 inline ModelSIR<TSeq> & ModelSIR<TSeq>::initial_states(
24089  std::vector< double > proportions_,
24090  std::vector< int > /* queue_ */
24091 ) {
24092 
24094  create_init_function_sir<TSeq>(proportions_)
24095  ;
24096 
24097  return *this;
24098 
24099 }
24100 
24101 #endif
24102 /*//////////////////////////////////////////////////////////////////////////////
24104 
24105  End of -include/epiworld/models/sir.hpp-
24106 
24109 
24110 
24111 /*//////////////////////////////////////////////////////////////////////////////
24113 
24114  Start of -include/epiworld/models/seir.hpp-
24115 
24118 
24119 
24120 #ifndef EPIWORLD_MODELS_SEIR_HPP
24121 #define EPIWORLD_MODELS_SEIR_HPP
24122 
24133 template<typename TSeq = EPI_DEFAULT_TSEQ>
24134 class ModelSEIR : public epiworld::Model<TSeq>
24135 {
24136 
24137 public:
24138  static const int SUSCEPTIBLE = 0;
24139  static const int EXPOSED = 1;
24140  static const int INFECTED = 2;
24141  static const int REMOVED = 3;
24142 
24143  ModelSEIR() {};
24144 
24145  ModelSEIR(
24146  ModelSEIR<TSeq> & model,
24147  const std::string & vname,
24148  epiworld_double prevalence,
24149  epiworld_double transmission_rate,
24150  epiworld_double avg_incubation_days,
24151  epiworld_double recovery_rate
24152  );
24153 
24154  ModelSEIR(
24155  const std::string & vname,
24156  epiworld_double prevalence,
24157  epiworld_double transmission_rate,
24158  epiworld_double avg_incubation_days,
24159  epiworld_double recovery_rate
24160  );
24161 
24162  epiworld::UpdateFun<TSeq> update_exposed_seir = [](
24163  epiworld::Agent<TSeq> * p,
24164  epiworld::Model<TSeq> * m
24165  ) -> void {
24166 
24167  // Getting the virus
24168  auto v = p->get_virus();
24169 
24170  // Does the agent become infected?
24171  if (m->runif() < 1.0/(v->get_incubation(m)))
24172  p->change_state(m, ModelSEIR<TSeq>::INFECTED);
24173 
24174  return;
24175  };
24176 
24177 
24178  epiworld::UpdateFun<TSeq> update_infected_seir = [](
24179  epiworld::Agent<TSeq> * p,
24180  epiworld::Model<TSeq> * m
24181  ) -> void {
24182  // Does the agent recover?
24183  if (m->runif() < (m->par("Recovery rate")))
24184  p->rm_virus(m);
24185 
24186  return;
24187  };
24188 
24195  ModelSEIR<TSeq> & initial_states(
24196  std::vector< double > proportions_,
24197  std::vector< int > queue_ = {}
24198  );
24199 
24200 };
24201 
24202 
24203 template<typename TSeq>
24204 inline ModelSEIR<TSeq>::ModelSEIR(
24205  ModelSEIR<TSeq> & model,
24206  const std::string & vname,
24207  epiworld_double prevalence,
24208  epiworld_double transmission_rate,
24209  epiworld_double avg_incubation_days,
24210  epiworld_double recovery_rate
24211  )
24212 {
24213 
24214  // Adding statuses
24215  model.add_state("Susceptible", epiworld::default_update_susceptible<TSeq>);
24216  model.add_state("Exposed", model.update_exposed_seir);
24217  model.add_state("Infected", model.update_infected_seir);
24218  model.add_state("Removed");
24219 
24220  // Setting up parameters
24221  model.add_param(transmission_rate, "Transmission rate");
24222  model.add_param(avg_incubation_days, "Incubation days");
24223  model.add_param(recovery_rate, "Recovery rate");
24224 
24225  // Preparing the virus -------------------------------------------
24226  epiworld::Virus<TSeq> virus(vname, prevalence, true);
24227  virus.set_state(ModelSEIR<TSeq>::EXPOSED, ModelSEIR<TSeq>::REMOVED, ModelSEIR<TSeq>::REMOVED);
24228 
24229  virus.set_prob_infecting(&model("Transmission rate"));
24230  virus.set_incubation(&model("Incubation days"));
24231  virus.set_prob_recovery(&model("Recovery rate"));
24232 
24233  // Adding the tool and the virus
24234  model.add_virus(virus);
24235 
24236  model.set_name("Susceptible-Exposed-Infected-Removed (SEIR)");
24237 
24238  return;
24239 
24240 }
24241 
24242 template<typename TSeq>
24243 inline ModelSEIR<TSeq>::ModelSEIR(
24244  const std::string & vname,
24245  epiworld_double prevalence,
24246  epiworld_double transmission_rate,
24247  epiworld_double avg_incubation_days,
24248  epiworld_double recovery_rate
24249  )
24250 {
24251 
24252  ModelSEIR<TSeq>(
24253  *this,
24254  vname,
24255  prevalence,
24256  transmission_rate,
24257  avg_incubation_days,
24258  recovery_rate
24259  );
24260 
24261  return;
24262 
24263 }
24264 
24265 template<typename TSeq>
24266 inline ModelSEIR<TSeq> & ModelSEIR<TSeq>::initial_states(
24267  std::vector< double > proportions_,
24268  std::vector< int > /**/
24269 ) {
24270 
24272  create_init_function_seir<TSeq>(proportions_)
24273  ;
24274 
24275  return *this;
24276 
24277 }
24278 
24279 #endif
24280 /*//////////////////////////////////////////////////////////////////////////////
24282 
24283  End of -include/epiworld/models/seir.hpp-
24284 
24287 
24288 
24289 /*//////////////////////////////////////////////////////////////////////////////
24291 
24292  Start of -include/epiworld/models/surveillance.hpp-
24293 
24296 
24297 
24298 #ifndef EPIWORLD_MODELS_SURVEILLANCE_HPP
24299 #define EPIWORLD_MODELS_SURVEILLANCE_HPP
24300 
24301 template<typename TSeq = EPI_DEFAULT_TSEQ>
24302 class ModelSURV : public epiworld::Model<TSeq> {
24303 
24304 private:
24305  // state
24306  static const int SUSCEPTIBLE = 0;
24307  static const int LATENT = 1;
24308  static const int SYMPTOMATIC = 2;
24309  static const int SYMPTOMATIC_ISOLATED = 3; // sampled and discovered
24310  static const int ASYMPTOMATIC = 4;
24311  static const int ASYMPTOMATIC_ISOLATED = 5;
24312  static const int RECOVERED = 6;
24313  static const int REMOVED = 7;
24314 
24315 public:
24316 
24321  std::vector< epiworld_double > days_latent_and_infectious;
24322 
24364  ModelSURV() {};
24365 
24366  ModelSURV(
24367  ModelSURV<TSeq> & model,
24368  const std::string & vname,
24369  epiworld_fast_uint prevalence = 50,
24370  epiworld_double efficacy_vax = 0.9,
24371  epiworld_double latent_period = 3u,
24372  epiworld_double infect_period = 6u,
24373  epiworld_double prob_symptoms = 0.6,
24374  epiworld_double prop_vaccinated = 0.25,
24375  epiworld_double prop_vax_redux_transm = 0.5,
24376  epiworld_double prop_vax_redux_infect = 0.5,
24377  epiworld_double surveillance_prob = 0.001,
24378  epiworld_double prob_transmission = 1.0,
24379  epiworld_double prob_death = 0.001,
24380  epiworld_double prob_noreinfect = 0.9
24381  );
24382 
24383  ModelSURV(
24384  const std::string & vname,
24385  epiworld_fast_uint prevalence = 50,
24386  epiworld_double efficacy_vax = 0.9,
24387  epiworld_double latent_period = 3u,
24388  epiworld_double infect_period = 6u,
24389  epiworld_double prob_symptoms = 0.6,
24390  epiworld_double prop_vaccinated = 0.25,
24391  epiworld_double prop_vax_redux_transm = 0.5,
24392  epiworld_double prop_vax_redux_infect = 0.5,
24393  epiworld_double surveillance_prob = 0.001,
24394  epiworld_double prob_transmission = 1.0,
24395  epiworld_double prob_death = 0.001,
24396  epiworld_double prob_noreinfect = 0.9
24397  );
24399 
24400  void reset();
24401 
24402 };
24403 
24404 template<typename TSeq>
24405 inline void ModelSURV<TSeq>::reset()
24406 {
24407  epiworld::Model<TSeq>::reset();
24408 
24409  days_latent_and_infectious.clear();
24410  days_latent_and_infectious.resize(
24411  2u * epiworld::Model<TSeq>::size(),
24412  -1.0
24413  );
24414 }
24415 
24416 template<typename TSeq>
24417 inline ModelSURV<TSeq>::ModelSURV(
24418  ModelSURV<TSeq> & model,
24419  const std::string & vname,
24420  epiworld_fast_uint prevalence,
24421  epiworld_double efficacy_vax,
24422  epiworld_double latent_period,
24423  epiworld_double infect_period,
24424  epiworld_double prob_symptoms,
24425  epiworld_double prop_vaccinated,
24426  epiworld_double prop_vax_redux_transm,
24427  epiworld_double prop_vax_redux_infect,
24428  epiworld_double surveillance_prob,
24429  epiworld_double prob_transmission,
24430  epiworld_double prob_death,
24431  epiworld_double prob_noreinfect
24432  )
24433 {
24434 
24435  EPI_NEW_UPDATEFUN_LAMBDA(surveillance_update_susceptible, TSeq) {
24436 
24437  // This computes the prob of getting any neighbor variant
24438  epiworld_fast_uint nviruses_tmp = 0u;
24439  for (auto & neighbor: p->get_neighbors())
24440  {
24441 
24442  auto & v = neighbor->get_virus();
24443 
24444  if (v == nullptr)
24445  continue;
24446 
24447  /* And it is a function of susceptibility_reduction as well */
24448  epiworld_double tmp_transmission =
24449  (1.0 - p->get_susceptibility_reduction(v, m)) *
24450  v->get_prob_infecting(m) *
24451  (1.0 - neighbor->get_transmission_reduction(v, m))
24452  ;
24453 
24454  m->array_double_tmp[nviruses_tmp] = tmp_transmission;
24455  m->array_virus_tmp[nviruses_tmp++] = &(*v);
24456  }
24457 
24458  // No virus to compute on
24459  if (nviruses_tmp == 0)
24460  return;
24461 
24462  // Running the roulette
24463  int which = roulette(nviruses_tmp, m);
24464 
24465  if (which < 0)
24466  return;
24467 
24468  p->set_virus(*m->array_virus_tmp[which], m);
24469  return;
24470 
24471  };
24472 
24473 
24474  epiworld::UpdateFun<TSeq> surveillance_update_exposed =
24475  [](epiworld::Agent<TSeq> * p, epiworld::Model<TSeq> * m) -> void
24476  {
24477 
24478  // Dynamically getting the ModelSURV
24479  ModelSURV<TSeq> * model_surv = dynamic_cast<ModelSURV<TSeq> *>(m);
24480 
24481  epiworld::VirusPtr<TSeq> & v = p->get_virus();
24482  epiworld_double p_die = v->get_prob_death(m) * (1.0 - p->get_death_reduction(v, m));
24483 
24484  epiworld_fast_uint days_since_exposed = m->today() - v->get_date();
24485  epiworld_fast_uint state = p->get_state();
24486 
24487  // Figuring out latent period
24488  auto & dat = model_surv->days_latent_and_infectious;
24489  if (dat[p->get_id()] < 0)
24490  {
24491  epiworld_double latent_days = m->rgamma(
24492  m->par("Latent period"), 1.0
24493  );
24494 
24495  dat[p->get_id() * 2u] = latent_days;
24496 
24497  dat[p->get_id() * 2u + 1u] =
24498  m->rgamma(m->par("Infect period"), 1.0) +
24499  latent_days;
24500  }
24501 
24502  // If still latent, nothing happens
24503  if (days_since_exposed <= dat[p->get_id() * 2u])
24504  return;
24505 
24506  // If past days infected + latent, then bye.
24507  if (days_since_exposed >= dat[p->get_id() * 2u + 1u])
24508  {
24509  p->rm_virus(m);
24510  return;
24511  }
24512 
24513  // If it is infected, then it can be asymptomatic or symptomatic
24514  if (state == ModelSURV<TSeq>::LATENT)
24515  {
24516 
24517  // Will be symptomatic?
24518  if (EPI_RUNIF() < m->par("Prob of symptoms"))
24519  p->change_state(m, ModelSURV<TSeq>::SYMPTOMATIC);
24520  else
24521  p->change_state(m, ModelSURV<TSeq>::ASYMPTOMATIC);
24522 
24523  return;
24524 
24525  }
24526 
24527  // Otherwise, it can be removed
24528  if (EPI_RUNIF() < p_die)
24529  {
24530  p->change_state(m, ModelSURV<TSeq>::REMOVED, -1);
24531  return;
24532  }
24533 
24534  return;
24535 
24536  };
24537 
24538  std::vector< unsigned int > exposed_state = {
24539  SYMPTOMATIC,
24540  SYMPTOMATIC_ISOLATED,
24541  ASYMPTOMATIC,
24542  ASYMPTOMATIC_ISOLATED,
24543  LATENT
24544  };
24545 
24546  epiworld::GlobalFun<TSeq> surveillance_program =
24547  [exposed_state](
24549  ) -> void
24550  {
24551 
24552  // How many will we find
24553  std::binomial_distribution<> bdist(m->size(), m->par("Surveilance prob."));
24554  int nsampled = bdist(*m->get_rand_endgine());
24555 
24556  int to_go = nsampled + 1;
24557 
24558  epiworld_double ndetected = 0.0;
24559  epiworld_double ndetected_asympt = 0.0;
24560 
24561  auto & pop = m->get_agents();
24562  std::vector< bool > sampled(m->size(), false);
24563 
24564  while (to_go-- > 0)
24565  {
24566 
24567  // Who is the lucky one
24568  epiworld_fast_uint i = static_cast<epiworld_fast_uint>(std::floor(EPI_RUNIF() * m->size()));
24569 
24570  if (sampled[i])
24571  continue;
24572 
24573  sampled[i] = true;
24574  epiworld::Agent<TSeq> * p = &pop[i];
24575 
24576  // If still exposed for the next term
24577  if (epiworld::IN(p->get_state(), exposed_state ))
24578  {
24579 
24580  ndetected += 1.0;
24581  if (p->get_state() == ModelSURV<TSeq>::ASYMPTOMATIC)
24582  {
24583  ndetected_asympt += 1.0;
24584  p->change_state(m, ModelSURV<TSeq>::ASYMPTOMATIC_ISOLATED);
24585  }
24586  else
24587  {
24588  p->change_state(m, ModelSURV<TSeq>::SYMPTOMATIC_ISOLATED);
24589  }
24590 
24591  }
24592 
24593  }
24594 
24595  // Writing the user data
24596  std::vector< int > totals;
24597  m->get_db().get_today_total(nullptr,&totals);
24598  m->add_user_data(
24599  {
24600  static_cast<epiworld_double>(nsampled),
24601  ndetected,
24602  ndetected_asympt,
24603  static_cast<epiworld_double>(totals[ModelSURV<TSeq>::ASYMPTOMATIC])
24604  }
24605  );
24606 
24607 
24608  };
24609 
24610  model.add_state("Susceptible", surveillance_update_susceptible);
24611  model.add_state("Latent", surveillance_update_exposed);
24612  model.add_state("Symptomatic", surveillance_update_exposed);
24613  model.add_state("Symptomatic isolated", surveillance_update_exposed);
24614  model.add_state("Asymptomatic", surveillance_update_exposed);
24615  model.add_state("Asymptomatic isolated", surveillance_update_exposed);
24616  model.add_state("Recovered");
24617  model.add_state("Removed");
24618 
24619  // General model parameters
24620  model.add_param(latent_period, "Latent period");
24621  model.add_param(infect_period, "Infect period");
24622  model.add_param(prob_symptoms, "Prob of symptoms");
24623  model.add_param(surveillance_prob, "Surveilance prob.");
24624  model.add_param(efficacy_vax, "Vax efficacy");
24625  model.add_param(prop_vax_redux_transm, "Vax redux transmission");
24626  model.add_param(prob_transmission, "Prob of transmission");
24627  model.add_param(prob_death, "Prob. death");
24628  model.add_param(prob_noreinfect, "Prob. no reinfect");
24629 
24630  // Virus ------------------------------------------------------------------
24631  epiworld::Virus<TSeq> covid("Covid19", prevalence, false);
24632  covid.set_state(LATENT, RECOVERED, REMOVED);
24633  covid.set_post_immunity(&model("Prob. no reinfect"));
24634  covid.set_prob_death(&model("Prob. death"));
24635 
24636  epiworld::VirusFun<TSeq> ptransmitfun = [](
24640  ) -> epiworld_double
24641  {
24642  // No chance of infecting
24643  epiworld_fast_uint s = p->get_state();
24644  if (s == ModelSURV<TSeq>::LATENT)
24645  return static_cast<epiworld_double>(0.0);
24647  return static_cast<epiworld_double>(0.0);
24649  return static_cast<epiworld_double>(0.0);
24650 
24651  // Otherwise
24652  return m->par("Prob of transmission");
24653  };
24654 
24655  covid.set_prob_infecting_fun(ptransmitfun);
24656 
24657  model.add_virus(covid);
24658 
24659  model.set_user_data({"nsampled", "ndetected", "ndetected_asympt", "nasymptomatic"});
24660  model.add_globalevent(surveillance_program, "Surveilance program", -1);
24661 
24662  // Vaccine tool -----------------------------------------------------------
24663  epiworld::Tool<TSeq> vax("Vaccine", prop_vaccinated, true);
24664  vax.set_susceptibility_reduction(&model("Vax efficacy"));
24665  vax.set_transmission_reduction(&model("Vax redux transmission"));
24666 
24667  model.add_tool(vax);
24668 
24669  model.set_name("Surveillance");
24670 
24671  return;
24672 
24673 }
24674 
24675 template<typename TSeq>
24677  const std::string & vname,
24678  epiworld_fast_uint prevalence,
24679  epiworld_double efficacy_vax,
24680  epiworld_double latent_period,
24681  epiworld_double infect_period,
24682  epiworld_double prob_symptoms,
24683  epiworld_double prop_vaccinated,
24684  epiworld_double prop_vax_redux_transm,
24685  epiworld_double prop_vax_redux_infect,
24686  epiworld_double surveillance_prob,
24687  epiworld_double prob_transmission,
24688  epiworld_double prob_death,
24689  epiworld_double prob_noreinfect
24690  )
24691 {
24692 
24693  ModelSURV(
24694  *this,
24695  vname,
24696  prevalence,
24697  efficacy_vax,
24698  latent_period,
24699  infect_period,
24700  prob_symptoms,
24701  prop_vaccinated,
24702  prop_vax_redux_transm,
24703  prop_vax_redux_infect,
24704  surveillance_prob,
24705  prob_transmission,
24706  prob_death,
24707  prob_noreinfect
24708  );
24709 
24710  return;
24711 
24712 }
24713 
24714 #endif
24715 /*//////////////////////////////////////////////////////////////////////////////
24717 
24718  End of -include/epiworld/models/surveillance.hpp-
24719 
24722 
24723 
24724 /*//////////////////////////////////////////////////////////////////////////////
24726 
24727  Start of -include/epiworld/models/sirconnected.hpp-
24728 
24731 
24732 
24733 #ifndef EPIWORLD_MODELS_SIRCONNECTED_HPP
24734 #define EPIWORLD_MODELS_SIRCONNECTED_HPP
24735 
24736 template<typename TSeq = EPI_DEFAULT_TSEQ>
24737 class ModelSIRCONN : public epiworld::Model<TSeq>
24738 {
24739 
24740 private:
24741 
24742  std::vector< epiworld::Agent<TSeq> * > infected;
24743  void update_infected();
24744 
24745 public:
24746 
24747  static const int SUSCEPTIBLE = 0;
24748  static const int INFECTED = 1;
24749  static const int RECOVERED = 2;
24750 
24751 
24752  ModelSIRCONN() {};
24753 
24754  ModelSIRCONN(
24755  ModelSIRCONN<TSeq> & model,
24756  const std::string & vname,
24757  epiworld_fast_uint n,
24758  epiworld_double prevalence,
24759  epiworld_double contact_rate,
24760  epiworld_double transmission_rate,
24761  epiworld_double recovery_rate
24762  );
24763 
24764  ModelSIRCONN(
24765  const std::string & vname,
24766  epiworld_fast_uint n,
24767  epiworld_double prevalence,
24768  epiworld_double contact_rate,
24769  epiworld_double transmission_rate,
24770  epiworld_double recovery_rate
24771  );
24772 
24773  ModelSIRCONN<TSeq> & run(
24774  epiworld_fast_uint ndays,
24775  int seed = -1
24776  );
24777 
24778  void reset();
24779 
24780  Model<TSeq> * clone_ptr();
24781 
24787  ModelSIRCONN<TSeq> & initial_states(
24788  std::vector< double > proportions_,
24789  std::vector< int > queue_ = {}
24790  );
24791 
24796  size_t get_n_infected() const
24797  {
24798  return infected.size();
24799  }
24800 
24801  /***
24802  * @brief Compute expected generation time
24803  * @param max_days Maximum number of days.
24804  * @param max_contacts Maximum number of contacts.
24805  */
24806  std::vector< double > generation_time_expected(
24807  int max_days = 200,
24808  int max_contacts = 200
24809  ) const;
24810 
24811 };
24812 
24813 template<typename TSeq>
24815 {
24816 
24817  infected.clear();
24818  infected.reserve(this->size());
24819 
24820  for (auto & p : this->get_agents())
24821  {
24822  if (p.get_state() == ModelSIRCONN<TSeq>::INFECTED)
24823  {
24824  infected.push_back(&p);
24825  }
24826  }
24827 
24829  this->get_n_infected(),
24830  static_cast<double>(Model<TSeq>::par("Contact rate"))/
24831  static_cast<double>(Model<TSeq>::size())
24832  );
24833 
24834  return;
24835 
24836 }
24837 
24838 template<typename TSeq>
24840  epiworld_fast_uint ndays,
24841  int seed
24842 )
24843 {
24844 
24845  Model<TSeq>::run(ndays, seed);
24846  return *this;
24847 
24848 }
24849 
24850 template<typename TSeq>
24852 {
24853 
24855 
24856  this->update_infected();
24857 
24858  return;
24859 
24860 }
24861 
24862 template<typename TSeq>
24864 {
24865 
24867  *dynamic_cast<const ModelSIRCONN<TSeq>*>(this)
24868  );
24869 
24870  return dynamic_cast< Model<TSeq> *>(ptr);
24871 
24872 }
24873 
24884 template<typename TSeq>
24886  ModelSIRCONN<TSeq> & model,
24887  const std::string & vname,
24888  epiworld_fast_uint n,
24889  epiworld_double prevalence,
24890  epiworld_double contact_rate,
24891  epiworld_double transmission_rate,
24892  epiworld_double recovery_rate
24893  // epiworld_double prob_reinfection
24894  )
24895 {
24896 
24897  epiworld::UpdateFun<TSeq> update_susceptible = [](
24899  ) -> void
24900  {
24901 
24902  int ndraw = m->rbinom();
24903 
24904  if (ndraw == 0)
24905  return;
24906 
24907  ModelSIRCONN<TSeq> * model = dynamic_cast<ModelSIRCONN<TSeq> *>(m);
24908  size_t ninfected = model->get_n_infected();
24909 
24910  // Drawing from the set
24911  int nviruses_tmp = 0;
24912  for (int i = 0; i < ndraw; ++i)
24913  {
24914  // Now selecting who is transmitting the disease
24915  int which = static_cast<int>(
24916  std::floor(ninfected * m->runif())
24917  );
24918 
24919  /* There is a bug in which runif() returns 1.0. It is rare, but
24920  * we saw it here. See the Notes section in the C++ manual
24921  * https://en.cppreference.com/mwiki/index.php?title=cpp/numeric/random/uniform_real_distribution&oldid=133329
24922  * And the reported bug in GCC:
24923  * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176
24924  *
24925  */
24926  if (which == static_cast<int>(ninfected))
24927  --which;
24928 
24929  epiworld::Agent<TSeq> & neighbor = *model->infected[which];
24930 
24931  // Can't sample itself
24932  if (neighbor.get_id() == p->get_id())
24933  continue;
24934 
24935  // The neighbor is infected because it is on the list!
24936  if (neighbor.get_virus() == nullptr)
24937  continue;
24938 
24939  auto & v = neighbor.get_virus();
24940 
24941  #ifdef EPI_DEBUG
24942  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
24943  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
24944  #endif
24945 
24946  /* And it is a function of susceptibility_reduction as well */
24947  m->array_double_tmp[nviruses_tmp] =
24948  (1.0 - p->get_susceptibility_reduction(v, m)) *
24949  v->get_prob_infecting(m) *
24950  (1.0 - neighbor.get_transmission_reduction(v, m))
24951  ;
24952 
24953  m->array_virus_tmp[nviruses_tmp++] = &(*v);
24954 
24955  }
24956 
24957  // No virus to compute
24958  if (nviruses_tmp == 0u)
24959  return;
24960 
24961  // Running the roulette
24962  int which = roulette(nviruses_tmp, m);
24963 
24964  if (which < 0)
24965  return;
24966 
24967  p->set_virus(*m->array_virus_tmp[which], m);
24968 
24969  return;
24970 
24971  };
24972 
24973 
24974  epiworld::UpdateFun<TSeq> update_infected = [](
24976  ) -> void {
24977 
24978  auto state = p->get_state();
24979 
24980  if (state == ModelSIRCONN<TSeq>::INFECTED)
24981  {
24982 
24983 
24984  // Odd: Die, Even: Recover
24985  epiworld_fast_uint n_events = 0u;
24986  // Recover
24987  m->array_double_tmp[n_events++] =
24988  1.0 - (1.0 - p->get_virus()->get_prob_recovery(m)) *
24989  (1.0 - p->get_recovery_enhancer(p->get_virus(), m));
24990 
24991  #ifdef EPI_DEBUG
24992  if (n_events == 0u)
24993  {
24994  printf_epiworld(
24995  "[epi-debug] agent %i has 0 possible events!!\n",
24996  static_cast<int>(p->get_id())
24997  );
24998  throw std::logic_error("Zero events in exposed.");
24999  }
25000  #else
25001  if (n_events == 0u)
25002  return;
25003  #endif
25004 
25005 
25006  // Running the roulette
25007  int which = roulette(n_events, m);
25008 
25009  if (which < 0)
25010  return;
25011 
25012  // Which roulette happen?
25013  p->rm_virus(m);
25014 
25015  return ;
25016 
25017  } else
25018  throw std::logic_error(
25019  "This function can only be applied to infected individuals. (SIR)"
25020  ) ;
25021 
25022  return;
25023 
25024  };
25025 
25026  // state
25027  model.add_state("Susceptible", update_susceptible);
25028  model.add_state("Infected", update_infected);
25029  model.add_state("Recovered");
25030 
25031  // Setting up parameters
25032  model.add_param(contact_rate, "Contact rate");
25033  model.add_param(transmission_rate, "Transmission rate");
25034  model.add_param(recovery_rate, "Recovery rate");
25035  // model.add_param(prob_reinfection, "Prob. Reinfection");
25036 
25037  // Adding update function
25038  epiworld::GlobalFun<TSeq> update = [](epiworld::Model<TSeq> * m) -> void
25039  {
25040  ModelSIRCONN<TSeq> * model = dynamic_cast<ModelSIRCONN<TSeq> *>(m);
25041  model->update_infected();
25042 
25043  return;
25044  };
25045 
25046  model.add_globalevent(update, "Update infected individuals");
25047 
25048  // Preparing the virus -------------------------------------------
25049  epiworld::Virus<TSeq> virus(vname, prevalence, true);
25050  virus.set_state(1, 2, 2);
25051  virus.set_prob_infecting(&model("Transmission rate"));
25052  virus.set_prob_recovery(&model("Recovery rate"));
25053 
25054  model.add_virus(virus);
25055 
25056  model.queuing_off(); // No queuing need
25057 
25058  model.agents_empty_graph(n);
25059 
25060  model.set_name("Susceptible-Infected-Removed (SIR) (connected)");
25061 
25062  return;
25063 
25064 }
25065 
25066 template<typename TSeq>
25068  const std::string & vname,
25069  epiworld_fast_uint n,
25070  epiworld_double prevalence,
25071  epiworld_double contact_rate,
25072  epiworld_double transmission_rate,
25073  epiworld_double recovery_rate
25074  )
25075 {
25076 
25077  ModelSIRCONN(
25078  *this,
25079  vname,
25080  n,
25081  prevalence,
25082  contact_rate,
25083  transmission_rate,
25084  recovery_rate
25085  );
25086 
25087  return;
25088 
25089 }
25090 
25091 template<typename TSeq>
25093  std::vector< double > proportions_,
25094  std::vector< int >
25095 ) {
25096 
25098  create_init_function_sir<TSeq>(proportions_)
25099  ;
25100 
25101  return *this;
25102 
25103 }
25104 
25105 template<typename TSeq>
25106 inline std::vector< double > ModelSIRCONN<TSeq>::generation_time_expected(
25107  int max_days,
25108  int max_contacts
25109 ) const
25110 {
25111 
25112  // Retrieving total counts
25113  std::vector< int > h_date;
25114  std::vector< std::string > h_state;
25115  std::vector< int > h_counts;
25116  const auto this_const = dynamic_cast<const ModelSIRCONN<TSeq> *>(this);
25117  this_const->get_db().get_hist_total(
25118  &h_date,
25119  &h_state,
25120  &h_counts
25121  );
25122 
25123  // Retrieving information on susceptibles
25124  std::vector< double > S(this_const->get_ndays(), 0.0);
25125  for (size_t i = 0; i < h_date.size(); ++i)
25126  {
25127  if (h_state[i] == "Susceptible")
25128  S[h_date[i]] += h_counts[i];
25129  }
25130 
25131  // The generation time in the SIR model starts from 1, as agents
25132  // spend at least one day in the infected state before starting
25133  // transmitting.
25134  std::vector< double > gen_times(this_const->get_ndays(), 1.0);
25135  double p_c = this_const->par("Contact rate")/this_const->size();
25136  double p_i = this_const->par("Transmission rate");
25137  double p_r = this_const->par("Recovery rate");
25138  for (size_t i = 0u; i < this_const->get_ndays(); ++i)
25139  {
25140  gen_times[i] = gen_int_mean(
25141  S[i],
25142  p_c,
25143  p_i,
25144  p_r,
25145  max_days,
25146  max_contacts
25147  );
25148 
25149  }
25150 
25151  return gen_times;
25152 
25153 }
25154 
25155 #endif
25156 /*//////////////////////////////////////////////////////////////////////////////
25158 
25159  End of -include/epiworld/models/sirconnected.hpp-
25160 
25163 
25164 
25165 /*//////////////////////////////////////////////////////////////////////////////
25167 
25168  Start of -include/epiworld/models/seirconnected.hpp-
25169 
25172 
25173 
25174 #ifndef EPIWORLD_MODELS_SEIRCONNECTED_HPP
25175 #define EPIWORLD_MODELS_SEIRCONNECTED_HPP
25176 
25177 template<typename TSeq = EPI_DEFAULT_TSEQ>
25178 class ModelSEIRCONN : public epiworld::Model<TSeq>
25179 {
25180 private:
25181  std::vector< epiworld::Agent<TSeq> * > infected;
25182  void update_infected();
25183 
25184 public:
25185 
25186  static const int SUSCEPTIBLE = 0;
25187  static const int EXPOSED = 1;
25188  static const int INFECTED = 2;
25189  static const int RECOVERED = 3;
25190 
25191 
25192  ModelSEIRCONN() {};
25193 
25194  ModelSEIRCONN(
25195  ModelSEIRCONN<TSeq> & model,
25196  const std::string & vname,
25197  epiworld_fast_uint n,
25198  epiworld_double prevalence,
25199  epiworld_double contact_rate,
25200  epiworld_double transmission_rate,
25201  epiworld_double avg_incubation_days,
25202  epiworld_double recovery_rate
25203  );
25204 
25205  ModelSEIRCONN(
25206  const std::string & vname,
25207  epiworld_fast_uint n,
25208  epiworld_double prevalence,
25209  epiworld_double contact_rate,
25210  epiworld_double transmission_rate,
25211  epiworld_double avg_incubation_days,
25212  epiworld_double recovery_rate
25213  );
25214 
25215  ModelSEIRCONN<TSeq> & run(
25216  epiworld_fast_uint ndays,
25217  int seed = -1
25218  );
25219 
25220  void reset();
25221 
25222  Model<TSeq> * clone_ptr();
25223 
25229  ModelSEIRCONN<TSeq> & initial_states(
25230  std::vector< double > proportions_,
25231  std::vector< int > queue_ = {}
25232  );
25233 
25234  size_t get_n_infected() const { return infected.size(); }
25235 
25236  /***
25237  * @brief Compute expected generation time
25238  * @param max_days Maximum number of days.
25239  * @param max_contacts Maximum number of contacts.
25240  */
25241  std::vector< double > generation_time_expected(
25242  int max_days = 200,
25243  int max_contacts = 200
25244  ) const;
25245 
25246 };
25247 
25248 template<typename TSeq>
25250 {
25251 
25252  infected.clear();
25253  infected.reserve(this->size());
25254 
25255  for (auto & p : this->get_agents())
25256  {
25257  if (p.get_state() == ModelSEIRCONN<TSeq>::INFECTED)
25258  {
25259  infected.push_back(&p);
25260  }
25261  }
25262 
25264  this->get_n_infected(),
25265  static_cast<double>(Model<TSeq>::par("Contact rate"))/
25266  static_cast<double>(Model<TSeq>::size())
25267  );
25268 
25269  return;
25270 
25271 }
25272 
25273 template<typename TSeq>
25275  epiworld_fast_uint ndays,
25276  int seed
25277 )
25278 {
25279 
25280  Model<TSeq>::run(ndays, seed);
25281 
25282  return *this;
25283 
25284 }
25285 
25286 template<typename TSeq>
25288 {
25289 
25291  this->update_infected();
25292 
25293  return;
25294 
25295 }
25296 
25297 template<typename TSeq>
25299 {
25300 
25302  *dynamic_cast<const ModelSEIRCONN<TSeq>*>(this)
25303  );
25304 
25305  return dynamic_cast< Model<TSeq> *>(ptr);
25306 
25307 }
25308 
25319 template<typename TSeq>
25321  ModelSEIRCONN<TSeq> & model,
25322  const std::string & vname,
25323  epiworld_fast_uint n,
25324  epiworld_double prevalence,
25325  epiworld_double contact_rate,
25326  epiworld_double transmission_rate,
25327  epiworld_double avg_incubation_days,
25328  epiworld_double recovery_rate
25329  // epiworld_double prob_reinfection
25330  )
25331 {
25332 
25333  epiworld::UpdateFun<TSeq> update_susceptible = [](
25335  ) -> void
25336  {
25337 
25338  // Sampling how many individuals
25339  int ndraw = m->rbinom();
25340 
25341  if (ndraw == 0)
25342  return;
25343 
25344  ModelSEIRCONN<TSeq> * model = dynamic_cast<ModelSEIRCONN<TSeq> *>(m);
25345  size_t ninfected = model->get_n_infected();
25346 
25347  // Drawing from the set
25348  int nviruses_tmp = 0;
25349  for (int i = 0; i < ndraw; ++i)
25350  {
25351  // Now selecting who is transmitting the disease
25352  int which = static_cast<int>(
25353  std::floor(ninfected * m->runif())
25354  );
25355 
25356  /* There is a bug in which runif() returns 1.0. It is rare, but
25357  * we saw it here. See the Notes section in the C++ manual
25358  * https://en.cppreference.com/mwiki/index.php?title=cpp/numeric/random/uniform_real_distribution&oldid=133329
25359  * And the reported bug in GCC:
25360  * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176
25361  *
25362  */
25363  if (which == static_cast<int>(ninfected))
25364  --which;
25365 
25366  epiworld::Agent<TSeq> & neighbor = *model->infected[which];
25367 
25368  // Can't sample itself
25369  if (neighbor.get_id() == p->get_id())
25370  continue;
25371 
25372  // The neighbor is infected by construction
25373  auto & v = neighbor.get_virus();
25374 
25375  #ifdef EPI_DEBUG
25376  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
25377  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
25378  #endif
25379 
25380  /* And it is a function of susceptibility_reduction as well */
25381  m->array_double_tmp[nviruses_tmp] =
25382  (1.0 - p->get_susceptibility_reduction(v, m)) *
25383  v->get_prob_infecting(m) *
25384  (1.0 - neighbor.get_transmission_reduction(v, m))
25385  ;
25386 
25387  m->array_virus_tmp[nviruses_tmp++] = &(*v);
25388 
25389  }
25390 
25391  // No virus to compute
25392  if (nviruses_tmp == 0u)
25393  return;
25394 
25395  // Running the roulette
25396  int which = roulette(nviruses_tmp, m);
25397 
25398  if (which < 0)
25399  return;
25400 
25401  p->set_virus(
25402  *m->array_virus_tmp[which],
25403  m,
25405  );
25406 
25407  return;
25408 
25409  };
25410 
25411  epiworld::UpdateFun<TSeq> update_infected = [](
25413  ) -> void {
25414 
25415  auto state = p->get_state();
25416 
25417  if (state == ModelSEIRCONN<TSeq>::EXPOSED)
25418  {
25419 
25420  // Getting the virus
25421  auto & v = p->get_virus();
25422 
25423  // Does the agent become infected?
25424  if (m->runif() < 1.0/(v->get_incubation(m)))
25425  {
25426 
25427  p->change_state(m, ModelSEIRCONN<TSeq>::INFECTED);
25428  return;
25429 
25430  }
25431 
25432 
25433  } else if (state == ModelSEIRCONN<TSeq>::INFECTED)
25434  {
25435 
25436 
25437  // Odd: Die, Even: Recover
25438  epiworld_fast_uint n_events = 0u;
25439  const auto & v = p->get_virus();
25440 
25441  // Recover
25442  m->array_double_tmp[n_events++] =
25443  1.0 - (1.0 - v->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(v, m));
25444 
25445  #ifdef EPI_DEBUG
25446  if (n_events == 0u)
25447  {
25448  printf_epiworld(
25449  "[epi-debug] agent %i has 0 possible events!!\n",
25450  static_cast<int>(p->get_id())
25451  );
25452  throw std::logic_error("Zero events in exposed.");
25453  }
25454  #else
25455  if (n_events == 0u)
25456  return;
25457  #endif
25458 
25459 
25460  // Running the roulette
25461  int which = roulette(n_events, m);
25462 
25463  if (which < 0)
25464  return;
25465 
25466  // Which roulette happen?
25467  p->rm_virus(m);
25468 
25469  return ;
25470 
25471  } else
25472  throw std::logic_error("This function can only be applied to exposed or infected individuals. (SEIR)") ;
25473 
25474  return;
25475 
25476  };
25477 
25478  // Setting up parameters
25479  model.add_param(contact_rate, "Contact rate");
25480  model.add_param(transmission_rate, "Prob. Transmission");
25481  model.add_param(recovery_rate, "Prob. Recovery");
25482  model.add_param(avg_incubation_days, "Avg. Incubation days");
25483 
25484  // state
25485  model.add_state("Susceptible", update_susceptible);
25486  model.add_state("Exposed", update_infected);
25487  model.add_state("Infected", update_infected);
25488  model.add_state("Recovered");
25489 
25490  // Adding update function
25491  epiworld::GlobalFun<TSeq> update = [](
25493  ) -> void
25494  {
25495 
25496  ModelSEIRCONN<TSeq> * model = dynamic_cast<ModelSEIRCONN<TSeq> *>(m);
25497 
25498  model->update_infected();
25499 
25500  return;
25501 
25502  };
25503 
25504  model.add_globalevent(update, "Update infected individuals");
25505 
25506 
25507  // Preparing the virus -------------------------------------------
25508  epiworld::Virus<TSeq> virus(vname, prevalence, true);
25509  virus.set_state(
25513  );
25514 
25515  virus.set_prob_infecting(&model("Prob. Transmission"));
25516  virus.set_prob_recovery(&model("Prob. Recovery"));
25517  virus.set_incubation(&model("Avg. Incubation days"));
25518 
25519  model.add_virus(virus);
25520 
25521  model.queuing_off(); // No queuing need
25522 
25523  // Adding the empty population
25524  model.agents_empty_graph(n);
25525 
25526  model.set_name("Susceptible-Exposed-Infected-Removed (SEIR) (connected)");
25527 
25528  return;
25529 
25530 }
25531 
25532 template<typename TSeq>
25534  const std::string & vname,
25535  epiworld_fast_uint n,
25536  epiworld_double prevalence,
25537  epiworld_double contact_rate,
25538  epiworld_double transmission_rate,
25539  epiworld_double avg_incubation_days,
25540  epiworld_double recovery_rate
25541  )
25542 {
25543 
25544  ModelSEIRCONN(
25545  *this,
25546  vname,
25547  n,
25548  prevalence,
25549  contact_rate,
25550  transmission_rate,
25551  avg_incubation_days,
25552  recovery_rate
25553  );
25554 
25555  return;
25556 
25557 }
25558 
25559 template<typename TSeq>
25561  std::vector< double > proportions_,
25562  std::vector< int > /* queue_ */
25563 )
25564 {
25565 
25567  create_init_function_seir<TSeq>(proportions_)
25568  ;
25569 
25570  return *this;
25571 
25572 }
25573 
25574 template<typename TSeq>
25575 inline std::vector< double > ModelSEIRCONN<TSeq>::generation_time_expected(
25576  int max_days,
25577  int max_contacts
25578 ) const
25579 {
25580 
25581  // Retrieving total counts
25582  std::vector< int > h_date;
25583  std::vector< std::string > h_state;
25584  std::vector< int > h_counts;
25585  const auto this_const = dynamic_cast<const ModelSEIRCONN<TSeq> *>(this);
25586  this_const->get_db().get_hist_total(
25587  &h_date,
25588  &h_state,
25589  &h_counts
25590  );
25591 
25592  // Retrieving information on susceptibles
25593  std::vector< double > S(this_const->get_ndays(), 0.0);
25594  for (size_t i = 0; i < h_date.size(); ++i)
25595  {
25596  if (h_state[i] == "Susceptible")
25597  S[h_date[i]] += h_counts[i];
25598  }
25599 
25600  // Computing the expected number of days in exposed
25601  double days_exposed = this_const->par("Avg. Incubation days");
25602 
25603  // The generation time in the SEIR model starts from 2, as agents
25604  // spend at least one day in the exposed state, and 1 day in the
25605  // infectious state before starting transmitting.
25606  std::vector< double > gen_times(
25607  this_const->get_ndays(), 1.0 + days_exposed
25608  );
25609 
25610  double p_c = this_const->par("Contact rate")/this_const->size();
25611  double p_i = this_const->par("Prob. Transmission");
25612  double p_r = this_const->par("Prob. Recovery");
25613 
25614  for (size_t i = 0u; i < this_const->get_ndays(); ++i)
25615  {
25616  gen_times[i] += gen_int_mean(
25617  S[i],
25618  p_c,
25619  p_i,
25620  p_r,
25621  max_days,
25622  max_contacts
25623  );
25624 
25625  }
25626 
25627  return gen_times;
25628 
25629 }
25630 
25631 #endif
25632 /*//////////////////////////////////////////////////////////////////////////////
25634 
25635  End of -include/epiworld/models/seirconnected.hpp-
25636 
25639 
25640 
25641 /*//////////////////////////////////////////////////////////////////////////////
25643 
25644  Start of -include/epiworld/models/sird.hpp-
25645 
25648 
25649 
25650 #ifndef EPIWORLD_SIRD_H
25651 #define EPIWORLD_SIRD_H
25652 
25656 template<typename TSeq = EPI_DEFAULT_TSEQ>
25657 class ModelSIRD : public epiworld::Model<TSeq>
25658 {
25659 public:
25660 
25661  ModelSIRD() {};
25662 
25663 
25675  ModelSIRD(
25676  ModelSIRD<TSeq> & model,
25677  const std::string & vname,
25678  epiworld_double prevalence,
25679  epiworld_double transmission_rate,
25680  epiworld_double recovery_rate,
25681  epiworld_double death_rate
25682  );
25683 
25684  ModelSIRD(
25685  const std::string & vname,
25686  epiworld_double prevalence,
25687  epiworld_double transmission_rate,
25688  epiworld_double recovery_rate,
25689  epiworld_double death_rate
25690  );
25692 
25699  ModelSIRD<TSeq> & initial_states(
25700  std::vector< double > proportions_,
25701  std::vector< int > queue_ = {}
25702  );
25703 
25704 };
25705 
25706 template<typename TSeq>
25707 inline ModelSIRD<TSeq>::ModelSIRD(
25708  ModelSIRD<TSeq> & model,
25709  const std::string & vname,
25710  epiworld_double prevalence,
25711  epiworld_double transmission_rate,
25712  epiworld_double recovery_rate,
25713  epiworld_double death_rate
25714  )
25715 {
25716 
25717  // Adding statuses
25718  model.add_state("Susceptible", epiworld::default_update_susceptible<TSeq>);
25719  model.add_state("Infected", epiworld::default_update_exposed<TSeq>);
25720  model.add_state("Recovered"),
25721  model.add_state("Deceased")
25722  ;
25723 
25724  // Setting up parameters
25725  model.add_param(recovery_rate, "Recovery rate");
25726  model.add_param(transmission_rate, "Transmission rate"),
25727  model.add_param(death_rate, "Death rate");
25728 
25729  // Preparing the virus -------------------------------------------
25730  epiworld::Virus<TSeq> virus(vname, prevalence, true);
25731  virus.set_state(1,2,3);
25732  virus.set_prob_recovery(&model("Recovery rate"));
25733  virus.set_prob_infecting(&model("Transmission rate"));
25734  virus.set_prob_death(&model("Death rate"));
25735 
25736  model.add_virus(virus);
25737 
25738  model.set_name("Susceptible-Infected-Recovered-Deceased (SIRD)");
25739 
25740  return;
25741 
25742 }
25743 
25744 template<typename TSeq>
25745 inline ModelSIRD<TSeq>::ModelSIRD(
25746  const std::string & vname,
25747  epiworld_double prevalence,
25748  epiworld_double transmission_rate,
25749  epiworld_double recovery_rate,
25750  epiworld_double death_rate
25751  )
25752 {
25753 
25754  ModelSIRD<TSeq>(
25755  *this,
25756  vname,
25757  prevalence,
25758  transmission_rate,
25759  recovery_rate,
25760  death_rate
25761  );
25762 
25763  return;
25764 
25765 }
25766 
25767 template<typename TSeq>
25768 inline ModelSIRD<TSeq> & ModelSIRD<TSeq>::initial_states(
25769  std::vector< double > proportions_,
25770  std::vector< int > /**/
25771 ) {
25772 
25774  create_init_function_sird<TSeq>(proportions_)
25775  ;
25776 
25777  return *this;
25778 
25779 }
25780 
25781 #endif
25782 /*//////////////////////////////////////////////////////////////////////////////
25784 
25785  End of -include/epiworld/models/sird.hpp-
25786 
25789 
25790 
25791 /*//////////////////////////////////////////////////////////////////////////////
25793 
25794  Start of -include/epiworld/models/sisd.hpp-
25795 
25798 
25799 
25800 #ifndef EPIWORLD_MODELS_SISD_HPP
25801 #define EPIWORLD_MODELS_SISD_HPP
25802 
25812 template<typename TSeq = EPI_DEFAULT_TSEQ>
25813 class ModelSISD : public epiworld::Model<TSeq>
25814 {
25815 
25816 public:
25817 
25818  ModelSISD() {};
25819 
25820  ModelSISD(
25821  ModelSISD<TSeq> & model,
25822  const std::string & vname,
25823  epiworld_double prevalence,
25824  epiworld_double transmission_rate,
25825  epiworld_double recovery_rate,
25826  epiworld_double death_rate
25827  );
25828 
25829  ModelSISD(
25830  const std::string & vname,
25831  epiworld_double prevalence,
25832  epiworld_double transmission_rate,
25833  epiworld_double recovery_rate,
25834  epiworld_double death_rate
25835  );
25836 
25837 };
25838 
25839 template<typename TSeq>
25840 inline ModelSISD<TSeq>::ModelSISD(
25841  ModelSISD<TSeq> & model,
25842  const std::string & vname,
25843  epiworld_double prevalence,
25844  epiworld_double transmission_rate,
25845  epiworld_double recovery_rate,
25846  epiworld_double death_rate
25847  )
25848 {
25849 
25850  model.set_name("Susceptible-Infected-Susceptible-Deceased (SISD)");
25851 
25852  // Adding statuses
25853  model.add_state("Susceptible", epiworld::default_update_susceptible<TSeq>);
25854  model.add_state("Infected", epiworld::default_update_exposed<TSeq>);
25855  model.add_state("Deceased");
25856 
25857  // Setting up parameters
25858  model.add_param(transmission_rate, "Transmission rate");
25859  model.add_param(recovery_rate, "Recovery rate");
25860  model.add_param(death_rate, "Death rate");
25861 
25862  // Preparing the virus -------------------------------------------
25863  epiworld::Virus<TSeq> virus(vname, prevalence, true);
25864  virus.set_state(1,0,2);
25865 
25866  virus.set_prob_infecting(&model("Transmission rate"));
25867  virus.set_prob_recovery(&model("Recovery rate"));
25868  virus.set_prob_death(0.01);
25869 
25870  model.add_virus(virus);
25871 
25872  return;
25873 
25874 }
25875 
25876 template<typename TSeq>
25877 inline ModelSISD<TSeq>::ModelSISD(
25878  const std::string & vname,
25879  epiworld_double prevalence,
25880  epiworld_double transmission_rate,
25881  epiworld_double recovery_rate,
25882  epiworld_double death_rate
25883  )
25884 {
25885 
25886  ModelSISD<TSeq>(
25887  *this,
25888  vname,
25889  prevalence,
25890  transmission_rate,
25891  recovery_rate,
25892  death_rate
25893  );
25894 
25895  return;
25896 
25897 }
25898 
25899 #endif
25900 /*//////////////////////////////////////////////////////////////////////////////
25902 
25903  End of -include/epiworld/models/sisd.hpp-
25904 
25907 
25908 
25909 /*//////////////////////////////////////////////////////////////////////////////
25911 
25912  Start of -include/epiworld/models/seird.hpp-
25913 
25916 
25917 
25918 #ifndef EPIWORLD_MODELS_SEIRD_HPP
25919 #define EPIWORLD_MODELS_SEIRD_HPP
25920 
25924 template<typename TSeq = EPI_DEFAULT_TSEQ>
25925 class ModelSEIRD : public epiworld::Model<TSeq>
25926 {
25927 
25928 public:
25929  static const int SUSCEPTIBLE = 0;
25930  static const int EXPOSED = 1;
25931  static const int INFECTED = 2;
25932  static const int REMOVED = 3;
25933  static const int DECEASED = 4;
25934 
25935  ModelSEIRD() {};
25936 
25949  ModelSEIRD(
25950  ModelSEIRD<TSeq> & model,
25951  const std::string & vname,
25952  epiworld_double prevalence,
25953  epiworld_double transmission_rate,
25954  epiworld_double avg_incubation_days,
25955  epiworld_double recovery_rate,
25956  epiworld_double death_rate
25957  );
25958 
25969  ModelSEIRD(
25970  const std::string & vname,
25971  epiworld_double prevalence,
25972  epiworld_double transmission_rate,
25973  epiworld_double avg_incubation_days,
25974  epiworld_double recovery_rate,
25975  epiworld_double death_rate
25976  );
25977 
25978  epiworld::UpdateFun<TSeq> update_exposed_seir = [](
25979  epiworld::Agent<TSeq> * p,
25980  epiworld::Model<TSeq> * m
25981  ) -> void {
25982 
25983  // Getting the virus
25984  auto v = p->get_virus();
25985 
25986  // Does the agent become infected?
25987  if (m->runif() < 1.0/(v->get_incubation(m)))
25988  p->change_state(m, ModelSEIRD<TSeq>::INFECTED);
25989 
25990  return;
25991  };
25992 
25993 
25994  epiworld::UpdateFun<TSeq> update_infected = [](
25995  epiworld::Agent<TSeq> * p, epiworld::Model<TSeq> * m
25996  ) -> void {
25997 
25998  // Odd: Die, Even: Recover
25999  epiworld_fast_uint n_events = 0u;
26000 
26001  const auto & v = p->get_virus();
26002 
26003  // Die
26004  m->array_double_tmp[n_events++] =
26005  v->get_prob_death(m) * (1.0 - p->get_death_reduction(v, m));
26006 
26007  // Recover
26008  m->array_double_tmp[n_events++] =
26009  1.0 - (1.0 - v->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(v, m));
26010 
26011 
26012 #ifdef EPI_DEBUG
26013  if (n_events == 0u)
26014  {
26015  printf_epiworld(
26016  "[epi-debug] agent %i has 0 possible events!!\n",
26017  static_cast<int>(p->get_id())
26018  );
26019  throw std::logic_error("Zero events in exposed.");
26020  }
26021 #else
26022  if (n_events == 0u)
26023  return;
26024 #endif
26025 
26026 
26027  // Running the roulette
26028  int which = roulette(n_events, m);
26029 
26030  if (which < 0)
26031  return;
26032 
26033  // Which roulette happen?
26034  if ((which % 2) == 0) // If odd
26035  {
26036 
26037  p->rm_agent_by_virus(m);
26038 
26039  } else {
26040 
26041  p->rm_virus(m);
26042 
26043  }
26044 
26045  return ;
26046 
26047 
26048 
26049  return;
26050 
26051  };
26052 
26053  ModelSEIRD<TSeq> & initial_states(
26054  std::vector< double > proportions_,
26055  std::vector< int > queue_ = {}
26056  );
26057 
26058 };
26059 
26060 
26061 
26062 template<typename TSeq>
26063 inline ModelSEIRD<TSeq>::ModelSEIRD(
26064  ModelSEIRD<TSeq> & model,
26065  const std::string & vname,
26066  epiworld_double prevalence,
26067  epiworld_double transmission_rate,
26068  epiworld_double avg_incubation_days,
26069  epiworld_double recovery_rate,
26070  epiworld_double death_rate
26071 )
26072 {
26073 
26074  // Adding statuses
26075  model.add_state("Susceptible", epiworld::default_update_susceptible<TSeq>);
26076  model.add_state("Exposed", model.update_exposed_seir);
26077  model.add_state("Infected", model.update_infected);
26078  model.add_state("Removed");
26079  model.add_state("Deceased");
26080 
26081  // Setting up parameters
26082  model.add_param(transmission_rate, "Transmission rate");
26083  model.add_param(avg_incubation_days, "Incubation days");
26084  model.add_param(recovery_rate, "Recovery rate");
26085  model.add_param(death_rate, "Death rate");
26086 
26087  // Preparing the virus -------------------------------------------
26088  epiworld::Virus<TSeq> virus(vname, prevalence, true);
26089  virus.set_state(ModelSEIRD<TSeq>::EXPOSED, ModelSEIRD<TSeq>::REMOVED, ModelSEIRD<TSeq>::DECEASED);
26090 
26091  virus.set_prob_infecting(&model("Transmission rate"));
26092  virus.set_incubation(&model("Incubation days"));
26093  virus.set_prob_death(&model("Death rate"));
26094  virus.set_prob_recovery(&model("Recovery rate"));
26095 
26096  // Adding the tool and the virus
26097  model.add_virus(virus);
26098 
26099  model.set_name("Susceptible-Exposed-Infected-Removed-Deceased (SEIRD)");
26100 
26101  return;
26102 
26103 }
26104 
26105 template<typename TSeq>
26106 inline ModelSEIRD<TSeq>::ModelSEIRD(
26107  const std::string & vname,
26108  epiworld_double prevalence,
26109  epiworld_double transmission_rate,
26110  epiworld_double avg_incubation_days,
26111  epiworld_double recovery_rate,
26112  epiworld_double death_rate
26113 )
26114 {
26115 
26116  ModelSEIRD<TSeq>(
26117  *this,
26118  vname,
26119  prevalence,
26120  transmission_rate,
26121  avg_incubation_days,
26122  recovery_rate,
26123  death_rate
26124  );
26125 
26126  return;
26127 
26128 }
26129 
26130 template<typename TSeq>
26131 inline ModelSEIRD<TSeq> & ModelSEIRD<TSeq>::initial_states(
26132  std::vector< double > proportions_,
26133  std::vector< int > /**/
26134 ) {
26135 
26137  create_init_function_seird<TSeq>(proportions_)
26138  ;
26139 
26140  return *this;
26141 
26142 }
26143 
26144 
26145 #endif
26146 /*//////////////////////////////////////////////////////////////////////////////
26148 
26149  End of -include/epiworld/models/seird.hpp-
26150 
26153 
26154 
26155 /*//////////////////////////////////////////////////////////////////////////////
26157 
26158  Start of -include/epiworld/models/sirdconnected.hpp-
26159 
26162 
26163 
26164 #ifndef EPIWORLD_MODELS_SIRDCONNECTED_HPP
26165 #define EPIWORLD_MODELS_SIRDCONNECTED_HPP
26166 
26167 template<typename TSeq = EPI_DEFAULT_TSEQ>
26168 class ModelSIRDCONN : public epiworld::Model<TSeq>
26169 {
26170 public:
26171  static const int SUSCEPTIBLE = 0;
26172  static const int INFECTED = 1;
26173  static const int RECOVERED = 2;
26174  static const int DECEASED = 3;
26175 
26176  ModelSIRDCONN() {
26177 
26178  // tracked_agents_infected.reserve(1e4);
26179  // tracked_agents_infected_next.reserve(1e4);
26180 
26181  };
26182 
26183  ModelSIRDCONN(
26184  ModelSIRDCONN<TSeq> & model,
26185  const std::string & vname,
26186  epiworld_fast_uint n,
26187  epiworld_double prevalence,
26188  epiworld_double contact_rate,
26189  epiworld_double transmission_rate,
26190  epiworld_double recovery_rate,
26191  epiworld_double death_rate
26192  );
26193 
26194  ModelSIRDCONN(
26195  const std::string & vname,
26196  epiworld_fast_uint n,
26197  epiworld_double prevalence,
26198  epiworld_double contact_rate,
26199  epiworld_double transmission_rate,
26200  epiworld_double recovery_rate,
26201  epiworld_double death_rate
26202  );
26203 
26204  // Tracking who is infected and who is not
26205  // std::vector< epiworld::Agent<TSeq>* > tracked_agents_infected = {};
26206  // std::vector< epiworld::Agent<TSeq>* > tracked_agents_infected_next = {};
26207  // std::vector< epiworld_double > tracked_agents_weight = {};
26208  // std::vector< epiworld_double > tracked_agents_weight_next = {};
26209 
26210  // int tracked_ninfected = 0;
26211  // int tracked_ninfected_next = 0;
26212  // epiworld_double tracked_current_infect_prob = 0.0;
26213 
26214  ModelSIRDCONN<TSeq> & run(
26215  epiworld_fast_uint ndays,
26216  int seed = -1
26217  );
26218 
26219  void reset();
26220 
26221  Model<TSeq> * clone_ptr();
26222 
26223 
26224 };
26225 
26226 template<typename TSeq>
26227 inline ModelSIRDCONN<TSeq> & ModelSIRDCONN<TSeq>::run(
26228  epiworld_fast_uint ndays,
26229  int seed
26230 )
26231 {
26232 
26233  Model<TSeq>::run(ndays, seed);
26234 
26235  return *this;
26236 
26237 }
26238 
26239 template<typename TSeq>
26240 inline void ModelSIRDCONN<TSeq>::reset()
26241 {
26242 
26243  Model<TSeq>::reset();
26244 
26245  // Model<TSeq>::set_rand_binom(
26246  // Model<TSeq>::size(),
26247  // static_cast<double>(
26248  // Model<TSeq>::par("Contact rate"))/
26249  // static_cast<double>(Model<TSeq>::size())
26250  // );
26251 
26252  return;
26253 
26254 }
26255 
26256 template<typename TSeq>
26257 inline Model<TSeq> * ModelSIRDCONN<TSeq>::clone_ptr()
26258 {
26259 
26260  ModelSIRDCONN<TSeq> * ptr = new ModelSIRDCONN<TSeq>(
26261  *dynamic_cast<const ModelSIRDCONN<TSeq>*>(this)
26262  );
26263 
26264  return dynamic_cast< Model<TSeq> *>(ptr);
26265 
26266 }
26267 
26279 template<typename TSeq>
26280 inline ModelSIRDCONN<TSeq>::ModelSIRDCONN(
26281  ModelSIRDCONN<TSeq> & model,
26282  const std::string & vname,
26283  epiworld_fast_uint n,
26284  epiworld_double prevalence,
26285  epiworld_double contact_rate,
26286  epiworld_double transmission_rate,
26287  epiworld_double recovery_rate,
26288  epiworld_double death_rate
26289  // epiworld_double prob_reinfection
26290  )
26291 {
26292 
26293 
26294 
26295  epiworld::UpdateFun<TSeq> update_susceptible = [](
26296  epiworld::Agent<TSeq> * p, epiworld::Model<TSeq> * m
26297  ) -> void
26298  {
26299 
26300  // Sampling how many individuals
26301  m->set_rand_binom(
26302  m->size(),
26303  static_cast<double>(
26304  m->par("Contact rate"))/
26305  static_cast<double>(m->size())
26306  );
26307 
26308  int ndraw = m->rbinom();
26309 
26310  if (ndraw == 0)
26311  return;
26312 
26313  // Drawing from the set
26314  int nviruses_tmp = 0;
26315  for (int i = 0; i < ndraw; ++i)
26316  {
26317  // Now selecting who is transmitting the disease
26318  int which = static_cast<int>(
26319  std::floor(m->size() * m->runif())
26320  );
26321 
26322  /* There is a bug in which runif() returns 1.0. It is rare, but
26323  * we saw it here. See the Notes section in the C++ manual
26324  * https://en.cppreference.com/mwiki/index.php?title=cpp/numeric/random/uniform_real_distribution&oldid=133329
26325  * And the reported bug in GCC:
26326  * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176
26327  *
26328  */
26329  if (which == static_cast<int>(m->size()))
26330  --which;
26331 
26332  // Can't sample itself
26333  if (which == static_cast<int>(p->get_id()))
26334  continue;
26335 
26336  // If the neighbor is infected, then proceed
26337  auto & neighbor = m->get_agents()[which];
26338  if (neighbor.get_state() == ModelSIRDCONN<TSeq>::INFECTED)
26339  {
26340 
26341  const auto & v = neighbor.get_virus();
26342 
26343  #ifdef EPI_DEBUG
26344  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
26345  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
26346  #endif
26347 
26348  /* And it is a function of susceptibility_reduction as well */
26349  m->array_double_tmp[nviruses_tmp] =
26350  (1.0 - p->get_susceptibility_reduction(v, m)) *
26351  v->get_prob_infecting(m) *
26352  (1.0 - neighbor.get_transmission_reduction(v, m))
26353  ;
26354 
26355  m->array_virus_tmp[nviruses_tmp++] = &(*v);
26356 
26357  }
26358  }
26359 
26360  // No virus to compute
26361  if (nviruses_tmp == 0u)
26362  return;
26363 
26364  // Running the roulette
26365  int which = roulette(nviruses_tmp, m);
26366 
26367  if (which < 0)
26368  return;
26369 
26370  p->set_virus(*m->array_virus_tmp[which], m);
26371 
26372  return;
26373 
26374  };
26375 
26376 
26377  epiworld::UpdateFun<TSeq> update_infected = [](
26379  ) -> void {
26380 
26381  auto state = p->get_state();
26382 
26383  if (state == ModelSIRDCONN<TSeq>::INFECTED)
26384  {
26385 
26386 
26387  // Odd: Die, Even: Recover
26388  epiworld_fast_uint n_events = 0u;
26389  const auto & v = p->get_virus();
26390 
26391  // Die
26392  m->array_double_tmp[n_events++] =
26393  v->get_prob_death(m) * (1.0 - p->get_death_reduction(v, m));
26394 
26395  // Recover
26396  m->array_double_tmp[n_events++] =
26397  1.0 - (1.0 - v->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(v, m));
26398 
26399  #ifdef EPI_DEBUG
26400  if (n_events == 0u)
26401  {
26402  printf_epiworld(
26403  "[epi-debug] agent %i has 0 possible events!!\n",
26404  static_cast<int>(p->get_id())
26405  );
26406  throw std::logic_error("Zero events in exposed.");
26407  }
26408  #else
26409  if (n_events == 0u)
26410  return;
26411  #endif
26412 
26413 
26414  // Running the roulette
26415  int which = roulette(n_events, m);
26416 
26417  if (which < 0)
26418  return;
26419 
26420  // Which roulette happen?
26421  if ((which % 2) == 0) // If odd
26422  {
26423 
26424  p->rm_agent_by_virus(m);
26425 
26426  } else {
26427 
26428  p->rm_virus(m);
26429 
26430  }
26431 
26432  return ;
26433 
26434  } else
26435  throw std::logic_error("This function can only be applied to infected individuals. (SIR)") ;
26436 
26437  return;
26438 
26439  };
26440 
26441  // state
26442  model.add_state("Susceptible", update_susceptible);
26443  model.add_state("Infected", update_infected);
26444  model.add_state("Recovered");
26445  model.add_state("Deceased");
26446 
26447 
26448  // Setting up parameters
26449  model.add_param(contact_rate, "Contact rate");
26450  model.add_param(transmission_rate, "Transmission rate");
26451  model.add_param(recovery_rate, "Recovery rate");
26452  model.add_param(death_rate, "Death rate");
26453  // model.add_param(prob_reinfection, "Prob. Reinfection");
26454 
26455  // Preparing the virus -------------------------------------------
26456  epiworld::Virus<TSeq> virus(vname, prevalence, true);
26457  virus.set_state(1, 2, 3);
26458  virus.set_prob_infecting(&model("Transmission rate"));
26459  virus.set_prob_recovery(&model("Recovery rate"));
26460  virus.set_prob_death(&model("Death rate"));
26461 
26462  model.add_virus(virus);
26463 
26464  model.queuing_off(); // No queuing need
26465 
26466  model.agents_empty_graph(n);
26467 
26468  model.set_name("Susceptible-Infected-Removed-Deceased (SIRD) (connected)");
26469 
26470  return;
26471 
26472 }
26473 
26474 template<typename TSeq>
26476  const std::string & vname,
26477  epiworld_fast_uint n,
26478  epiworld_double prevalence,
26479  epiworld_double contact_rate,
26480  epiworld_double transmission_rate,
26481  epiworld_double recovery_rate,
26482  epiworld_double death_rate
26483  )
26484 {
26485 
26486  ModelSIRDCONN(
26487  *this,
26488  vname,
26489  n,
26490  prevalence,
26491  contact_rate,
26492  transmission_rate,
26493  recovery_rate,
26494  death_rate
26495  );
26496 
26497  return;
26498 
26499 }
26500 
26501 
26502 #endif
26503 /*//////////////////////////////////////////////////////////////////////////////
26505 
26506  End of -include/epiworld/models/sirdconnected.hpp-
26507 
26510 
26511 
26512 /*//////////////////////////////////////////////////////////////////////////////
26514 
26515  Start of -include/epiworld/models/seirdconnected.hpp-
26516 
26519 
26520 
26521 #ifndef EPIWORLD_MODELS_SEIRDCONNECTED_HPP
26522 #define EPIWORLD_MODELS_SEIRDCONNECTED_HPP
26523 
26524 template<typename TSeq = EPI_DEFAULT_TSEQ>
26525 class ModelSEIRDCONN : public epiworld::Model<TSeq>
26526 {
26527 private:
26528  std::vector< epiworld::Agent<TSeq> * > infected;
26529  void update_infected();
26530 
26531 public:
26532 
26533  static const int SUSCEPTIBLE = 0;
26534  static const int EXPOSED = 1;
26535  static const int INFECTED = 2;
26536  static const int REMOVED = 3;
26537  static const int DECEASED = 4;
26538 
26539  ModelSEIRDCONN() {};
26540 
26541  ModelSEIRDCONN(
26542  ModelSEIRDCONN<TSeq> & model,
26543  const std::string & vname,
26544  epiworld_fast_uint n,
26545  epiworld_double prevalence,
26546  epiworld_double contact_rate,
26547  epiworld_double transmission_rate,
26548  epiworld_double avg_incubation_days,
26549  epiworld_double recovery_rate,
26550  epiworld_double death_rate
26551  );
26552 
26553  ModelSEIRDCONN(
26554  const std::string & vname,
26555  epiworld_fast_uint n,
26556  epiworld_double prevalence,
26557  epiworld_double contact_rate,
26558  epiworld_double transmission_rate,
26559  epiworld_double avg_incubation_days,
26560  epiworld_double recovery_rate,
26561  epiworld_double death_rate
26562  );
26563 
26564  ModelSEIRDCONN<TSeq> & run(
26565  epiworld_fast_uint ndays,
26566  int seed = -1
26567  );
26568 
26569  void reset();
26570 
26571  Model<TSeq> * clone_ptr();
26572 
26579  ModelSEIRDCONN<TSeq> & initial_states(
26580  std::vector< double > proportions_,
26581  std::vector< int > queue_ = {}
26582  );
26583 
26584  size_t get_n_infected() const
26585  {
26586  return infected.size();
26587  }
26588 
26589 };
26590 
26591 template<typename TSeq>
26592 inline void ModelSEIRDCONN<TSeq>::update_infected()
26593 {
26594  infected.clear();
26595  infected.reserve(this->size());
26596 
26597  for (auto & p : this->get_agents())
26598  {
26599  if (p.get_state() == ModelSEIRDCONN<TSeq>::INFECTED)
26600  {
26601  infected.push_back(&p);
26602  }
26603  }
26604 
26605  Model<TSeq>::set_rand_binom(
26606  this->get_n_infected(),
26607  static_cast<double>(Model<TSeq>::par("Contact rate"))/
26608  static_cast<double>(Model<TSeq>::size())
26609  );
26610 
26611  return;
26612 }
26613 
26614 template<typename TSeq>
26615 inline ModelSEIRDCONN<TSeq> & ModelSEIRDCONN<TSeq>::run(
26616  epiworld_fast_uint ndays,
26617  int seed
26618 )
26619 {
26620 
26621  Model<TSeq>::run(ndays, seed);
26622 
26623  return *this;
26624 
26625 }
26626 
26627 template<typename TSeq>
26628 inline void ModelSEIRDCONN<TSeq>::reset()
26629 {
26630 
26631  Model<TSeq>::reset();
26632 
26633  this->update_infected();
26634 
26635  return;
26636 
26637 }
26638 
26639 template<typename TSeq>
26640 inline Model<TSeq> * ModelSEIRDCONN<TSeq>::clone_ptr()
26641 {
26642 
26643  ModelSEIRDCONN<TSeq> * ptr = new ModelSEIRDCONN<TSeq>(
26644  *dynamic_cast<const ModelSEIRDCONN<TSeq>*>(this)
26645  );
26646 
26647  return dynamic_cast< Model<TSeq> *>(ptr);
26648 
26649 }
26650 
26662 template<typename TSeq>
26663 inline ModelSEIRDCONN<TSeq>::ModelSEIRDCONN(
26664  ModelSEIRDCONN<TSeq> & model,
26665  const std::string & vname,
26666  epiworld_fast_uint n,
26667  epiworld_double prevalence,
26668  epiworld_double contact_rate,
26669  epiworld_double transmission_rate,
26670  epiworld_double avg_incubation_days,
26671  epiworld_double recovery_rate,
26672  epiworld_double death_rate
26673  // epiworld_double prob_reinfection
26674  )
26675 {
26676 
26677  epiworld::UpdateFun<TSeq> update_susceptible = [](
26678  epiworld::Agent<TSeq> * p, epiworld::Model<TSeq> * m
26679  ) -> void
26680  {
26681 
26682  // Sampling how many individuals
26683  int ndraw = m->rbinom();
26684 
26685  if (ndraw == 0)
26686  return;
26687 
26688  ModelSEIRDCONN<TSeq> * model = dynamic_cast<ModelSEIRDCONN<TSeq> *>(
26689  m
26690  );
26691 
26692  size_t ninfected = model->get_n_infected();
26693 
26694  // Drawing from the set
26695  int nviruses_tmp = 0;
26696  for (int i = 0; i < ndraw; ++i)
26697  {
26698  // Now selecting who is transmitting the disease
26699  int which = static_cast<int>(
26700  std::floor(ninfected * m->runif())
26701  );
26702 
26703  /* There is a bug in which runif() returns 1.0. It is rare, but
26704  * we saw it here. See the Notes section in the C++ manual
26705  * https://en.cppreference.com/mwiki/index.php?title=cpp/numeric/random/uniform_real_distribution&oldid=133329
26706  * And the reported bug in GCC:
26707  * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176
26708  *
26709  */
26710  if (which == static_cast<int>(ninfected))
26711  --which;
26712 
26713  epiworld::Agent<TSeq> & neighbor = *model->infected[which];
26714 
26715  // Can't sample itself
26716  if (neighbor.get_id() == p->get_id())
26717  continue;
26718 
26719  // All neighbors in this set are infected by construction
26720  const auto & v = neighbor.get_virus();
26721 
26722  #ifdef EPI_DEBUG
26723  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
26724  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
26725  #endif
26726 
26727  /* And it is a function of susceptibility_reduction as well */
26728  m->array_double_tmp[nviruses_tmp] =
26729  (1.0 - p->get_susceptibility_reduction(v, m)) *
26730  v->get_prob_infecting(m) *
26731  (1.0 - neighbor.get_transmission_reduction(v, m))
26732  ;
26733 
26734  m->array_virus_tmp[nviruses_tmp++] = &(*v);
26735  }
26736 
26737  // No virus to compute
26738  if (nviruses_tmp == 0u)
26739  return;
26740 
26741  // Running the roulette
26742  int which = roulette(nviruses_tmp, m);
26743 
26744  if (which < 0)
26745  return;
26746 
26747  p->set_virus(
26748  *m->array_virus_tmp[which],
26749  m,
26751  );
26752 
26753  return;
26754 
26755  };
26756 
26757  epiworld::UpdateFun<TSeq> update_infected = [](
26759  ) -> void {
26760 
26761  auto state = p->get_state();
26762 
26763  if (state == ModelSEIRDCONN<TSeq>::EXPOSED)
26764  {
26765 
26766  // Getting the virus
26767  auto & v = p->get_virus();
26768 
26769  // Does the agent become infected?
26770  if (m->runif() < 1.0/(v->get_incubation(m)))
26771  {
26772 
26773  p->change_state(m, ModelSEIRDCONN<TSeq>::INFECTED);
26774  return;
26775 
26776  }
26777 
26778 
26779  } else if (state == ModelSEIRDCONN<TSeq>::INFECTED)
26780  {
26781 
26782  // Odd: Die, Even: Recover
26783  epiworld_fast_uint n_events = 0u;
26784  const auto & v = p->get_virus();
26785 
26786  // Die
26787  m->array_double_tmp[n_events++] =
26788  v->get_prob_death(m) * (1.0 - p->get_death_reduction(v, m));
26789 
26790  // Recover
26791  m->array_double_tmp[n_events++] =
26792  1.0 - (1.0 - v->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(v, m));
26793 
26794  #ifdef EPI_DEBUG
26795  if (n_events == 0u)
26796  {
26797  printf_epiworld(
26798  "[epi-debug] agent %i has 0 possible events!!\n",
26799  static_cast<int>(p->get_id())
26800  );
26801  throw std::logic_error("Zero events in exposed.");
26802  }
26803  #else
26804  if (n_events == 0u)
26805  return;
26806  #endif
26807 
26808 
26809  // Running the roulette
26810  int which = roulette(n_events, m);
26811 
26812  if (which < 0)
26813  return;
26814 
26815  // Which roulette happen?
26816  if ((which % 2) == 0) // If odd
26817  {
26818 
26819  p->rm_agent_by_virus(m);
26820 
26821  } else {
26822 
26823  p->rm_virus(m);
26824 
26825  }
26826 
26827  return ;
26828 
26829  } else
26830  throw std::logic_error("This function can only be applied to exposed or infected individuals. (SEIRD)") ;
26831 
26832  return;
26833 
26834  };
26835 
26836  // Setting up parameters
26837  model.add_param(contact_rate, "Contact rate");
26838  model.add_param(transmission_rate, "Prob. Transmission");
26839  model.add_param(recovery_rate, "Prob. Recovery");
26840  model.add_param(avg_incubation_days, "Avg. Incubation days");
26841  model.add_param(death_rate, "Death rate");
26842 
26843  // state
26844  model.add_state("Susceptible", update_susceptible);
26845  model.add_state("Exposed", update_infected);
26846  model.add_state("Infected", update_infected);
26847  model.add_state("Removed");
26848  model.add_state("Deceased");
26849 
26850 
26851  // Adding update function
26852  epiworld::GlobalFun<TSeq> update = [](epiworld::Model<TSeq> * m) -> void
26853  {
26854  ModelSEIRDCONN<TSeq> * model = dynamic_cast<ModelSEIRDCONN<TSeq> *>(m);
26855 
26856  if (model == nullptr)
26857  throw std::logic_error(
26858  std::string("Internal error in the ModelSEIRDCONN model: ") +
26859  std::string("The model returns a null pointer.")
26860  );
26861  else
26862  model->update_infected();
26863 
26864  return;
26865  };
26866 
26867  model.add_globalevent(update, "Update infected individuals");
26868 
26869 
26870  // Preparing the virus -------------------------------------------
26871  epiworld::Virus<TSeq> virus(vname, prevalence, true);
26872  virus.set_state(
26876  );
26877 
26878  virus.set_prob_infecting(&model("Prob. Transmission"));
26879  virus.set_prob_recovery(&model("Prob. Recovery"));
26880  virus.set_incubation(&model("Avg. Incubation days"));
26881  virus.set_prob_death(&model("Death rate"));
26882  model.add_virus(virus);
26883 
26884  model.queuing_off(); // No queuing need
26885 
26886  // Adding the empty population
26887  model.agents_empty_graph(n);
26888 
26889  model.set_name("Susceptible-Exposed-Infected-Removed-Deceased (SEIRD) (connected)");
26890 
26891  return;
26892 
26893 }
26894 
26895 template<typename TSeq>
26897  const std::string & vname,
26898  epiworld_fast_uint n,
26899  epiworld_double prevalence,
26900  epiworld_double contact_rate,
26901  epiworld_double transmission_rate,
26902  epiworld_double avg_incubation_days,
26903  epiworld_double recovery_rate,
26904  epiworld_double death_rate
26905  )
26906 {
26907 
26909  *this,
26910  vname,
26911  n,
26912  prevalence,
26913  contact_rate,
26914  transmission_rate,
26915  avg_incubation_days,
26916  recovery_rate,
26917  death_rate
26918  );
26919 
26920  return;
26921 
26922 }
26923 
26924 template<typename TSeq>
26926  std::vector< double > proportions_,
26927  std::vector< int >
26928 ) {
26929 
26931  create_init_function_seird<TSeq>(proportions_)
26932  ;
26933 
26934  return *this;
26935 
26936 }
26937 
26938 #endif
26939 /*//////////////////////////////////////////////////////////////////////////////
26941 
26942  End of -include/epiworld/models/seirdconnected.hpp-
26943 
26946 
26947 
26948 /*//////////////////////////////////////////////////////////////////////////////
26950 
26951  Start of -include/epiworld/models/sirlogit.hpp-
26952 
26955 
26956 
26957 // #include "../epiworld.hpp"
26958 
26959 #ifndef EPIWORLD_MODELS_SIRLOGIT_HPP
26960 #define EPIWORLD_MODELS_SIRLOGIT_HPP
26961 
26962 
26990 template<typename TSeq = EPI_DEFAULT_TSEQ>
26991 class ModelSIRLogit : public epiworld::Model<TSeq>
26992 {
26993 private:
26994  static const int SUSCEPTIBLE = 0;
26995  static const int INFECTED = 1;
26996  static const int RECOVERED = 2;
26997 
26998 public:
26999 
27000  ModelSIRLogit() {};
27001 
27011  ModelSIRLogit(
27012  ModelSIRLogit<TSeq> & model,
27013  const std::string & vname,
27014  double * data,
27015  size_t ncols,
27016  std::vector< double > coefs_infect,
27017  std::vector< double > coefs_recover,
27018  std::vector< size_t > coef_infect_cols,
27019  std::vector< size_t > coef_recover_cols,
27020  epiworld_double transmission_rate,
27021  epiworld_double recovery_rate,
27022  epiworld_double prevalence
27023  );
27024 
27025  ModelSIRLogit(
27026  const std::string & vname,
27027  double * data,
27028  size_t ncols,
27029  std::vector< double > coefs_infect,
27030  std::vector< double > coefs_recover,
27031  std::vector< size_t > coef_infect_cols,
27032  std::vector< size_t > coef_recover_cols,
27033  epiworld_double transmission_rate,
27034  epiworld_double recovery_rate,
27035  epiworld_double prevalence
27036  );
27037 
27038  ModelSIRLogit<TSeq> & run(
27039  epiworld_fast_uint ndays,
27040  int seed = -1
27041  );
27042 
27043  Model<TSeq> * clone_ptr();
27044 
27045  void reset();
27046 
27047  std::vector< double > coefs_infect;
27048  std::vector< double > coefs_recover;
27049  std::vector< size_t > coef_infect_cols;
27050  std::vector< size_t > coef_recover_cols;
27051 
27052 };
27053 
27054 
27055 
27056 template<typename TSeq>
27057 inline ModelSIRLogit<TSeq> & ModelSIRLogit<TSeq>::run(
27058  epiworld_fast_uint ndays,
27059  int seed
27060 )
27061 {
27062 
27063  Model<TSeq>::run(ndays, seed);
27064  return *this;
27065 
27066 }
27067 
27068 template<typename TSeq>
27069 inline Model<TSeq> * ModelSIRLogit<TSeq>::clone_ptr()
27070 {
27071 
27072  ModelSIRLogit<TSeq> * ptr = new ModelSIRLogit<TSeq>(
27073  *dynamic_cast<const ModelSIRLogit<TSeq>*>(this)
27074  );
27075 
27076  return dynamic_cast< Model<TSeq> *>(ptr);
27077 
27078 }
27079 
27080 template<typename TSeq>
27081 inline void ModelSIRLogit<TSeq>::reset()
27082 {
27083 
27084  /* Checking specified columns in the model */
27085  for (const auto & c : coef_infect_cols)
27086  {
27088  throw std::range_error("Columns specified in coef_infect_cols out of range.");
27089  }
27090 
27091  for (const auto & c : coef_recover_cols)
27092  {
27094  throw std::range_error("Columns specified in coef_recover_cols out of range.");
27095  }
27096 
27097  /* Checking attributes */
27098  if (coefs_infect.size() != (coef_infect_cols.size() + 1u))
27099  throw std::logic_error(
27100  "The number of coefficients (infection) doesn't match the number of features. It must be as many features of the agents plus 1 (exposure.)"
27101  );
27102 
27103  if (coefs_recover.size() != coef_recover_cols.size())
27104  throw std::logic_error(
27105  "The number of coefficients (recovery) doesn't match the number of features. It must be as many features of the agents."
27106  );
27107 
27109 
27110  return;
27111 
27112 }
27113 
27124 template<typename TSeq>
27126  ModelSIRLogit<TSeq> & model,
27127  const std::string & vname,
27128  double * data,
27129  size_t ncols,
27130  std::vector< double > coefs_infect,
27131  std::vector< double > coefs_recover,
27132  std::vector< size_t > coef_infect_cols,
27133  std::vector< size_t > coef_recover_cols,
27134  epiworld_double transmission_rate,
27135  epiworld_double recovery_rate,
27136  epiworld_double prevalence
27137  )
27138 {
27139 
27140  if (coef_infect_cols.size() == 0u)
27141  throw std::logic_error("No columns specified for coef_infect_cols.");
27142 
27143  if (coef_recover_cols.size() == 0u)
27144  throw std::logic_error("No columns specified for coef_recover_cols.");
27145 
27146  // Saving the variables
27147  model.set_agents_data(
27148  data, ncols
27149  );
27150 
27151  model.coefs_infect = coefs_infect;
27152  model.coefs_recover = coefs_recover;
27153  model.coef_infect_cols = coef_infect_cols;
27154  model.coef_recover_cols = coef_recover_cols;
27155 
27156  epiworld::UpdateFun<TSeq> update_susceptible = [](
27158  ) -> void
27159  {
27160 
27161  // Getting the right type
27162  ModelSIRLogit<TSeq> * _m = dynamic_cast<ModelSIRLogit<TSeq>*>(m);
27163 
27164  // Exposure coefficient
27165  const double coef_exposure = _m->coefs_infect[0u];
27166 
27167  // This computes the prob of getting any neighbor variant
27168  size_t nviruses_tmp = 0u;
27169 
27170  double baseline = 0.0;
27171  for (size_t k = 0u; k < _m->coef_infect_cols.size(); ++k)
27172  baseline += p->operator[](k) * _m->coefs_infect[k + 1u];
27173 
27174  for (auto & neighbor: p->get_neighbors())
27175  {
27176 
27177  if (neighbor->get_virus() == nullptr)
27178  continue;
27179 
27180  auto & v = neighbor->get_virus();
27181 
27182  #ifdef EPI_DEBUG
27183  if (nviruses_tmp >= m->array_virus_tmp.size())
27184  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
27185  #endif
27186 
27187  /* And it is a function of susceptibility_reduction as well */
27188  m->array_double_tmp[nviruses_tmp] =
27189  baseline +
27190  (1.0 - p->get_susceptibility_reduction(v, m)) *
27191  v->get_prob_infecting(m) *
27192  (1.0 - neighbor->get_transmission_reduction(v, m)) *
27193  coef_exposure
27194  ;
27195 
27196  // Applying the plogis function
27197  m->array_double_tmp[nviruses_tmp] = 1.0/
27198  (1.0 + std::exp(-m->array_double_tmp[nviruses_tmp]));
27199 
27200  m->array_virus_tmp[nviruses_tmp++] = &(*v);
27201 
27202  }
27203 
27204  // No virus to compute
27205  if (nviruses_tmp == 0u)
27206  return;
27207 
27208  // Running the roulette
27209  int which = roulette(nviruses_tmp, m);
27210 
27211  if (which < 0)
27212  return;
27213 
27214  p->set_virus(*m->array_virus_tmp[which], m);
27215 
27216  return;
27217 
27218  };
27219 
27220  epiworld::UpdateFun<TSeq> update_infected = [](
27222  ) -> void
27223  {
27224 
27225  // Getting the right type
27226  ModelSIRLogit<TSeq> * _m = dynamic_cast<ModelSIRLogit<TSeq>*>(m);
27227 
27228  // Computing recovery probability once
27229  double prob = 0.0;
27230  #if defined(__OPENMP) || defined(_OPENMP)
27231  #pragma omp simd reduction(+:prob)
27232  #endif
27233  for (size_t i = 0u; i < _m->coefs_recover.size(); ++i)
27234  prob += p->operator[](i) * _m->coefs_recover[i];
27235 
27236  // Computing logis
27237  prob = 1.0/(1.0 + std::exp(-prob));
27238 
27239  if (prob > m->runif())
27240  p->rm_virus(m);
27241 
27242  return;
27243 
27244  };
27245 
27246  // state
27247  model.add_state("Susceptible", update_susceptible);
27248  model.add_state("Infected", update_infected);
27249  model.add_state("Recovered");
27250 
27251  // Setting up parameters
27252  // model.add_param(contact_rate, "Contact rate");
27253  model.add_param(transmission_rate, "Transmission rate");
27254  model.add_param(recovery_rate, "Recovery rate");
27255  // model.add_param(prob_reinfection, "Prob. Reinfection");
27256 
27257  // Preparing the virus -------------------------------------------
27258  epiworld::Virus<TSeq> virus(vname, prevalence, true);
27259  virus.set_state(
27263  );
27264 
27265  virus.set_prob_infecting(&model("Transmission rate"));
27266  virus.set_prob_recovery(&model("Recovery rate"));
27267 
27268  // virus.set_prob
27269 
27270  model.add_virus(virus);
27271 
27272  model.set_name("Susceptible-Infected-Removed (SIR) (logit)");
27273 
27274  return;
27275 
27276 }
27277 
27278 template<typename TSeq>
27280  const std::string & vname,
27281  double * data,
27282  size_t ncols,
27283  std::vector< double > coefs_infect,
27284  std::vector< double > coefs_recover,
27285  std::vector< size_t > coef_infect_cols,
27286  std::vector< size_t > coef_recover_cols,
27287  epiworld_double transmission_rate,
27288  epiworld_double recovery_rate,
27289  epiworld_double prevalence
27290  )
27291 {
27292 
27293  ModelSIRLogit(
27294  *this,
27295  vname,
27296  data,
27297  ncols,
27298  coefs_infect,
27299  coefs_recover,
27300  coef_infect_cols,
27301  coef_recover_cols,
27302  transmission_rate,
27303  recovery_rate,
27304  prevalence
27305  );
27306 
27307  return;
27308 
27309 }
27310 
27311 
27312 #endif
27313 /*//////////////////////////////////////////////////////////////////////////////
27315 
27316  End of -include/epiworld/models/sirlogit.hpp-
27317 
27320 
27321 
27322 /*//////////////////////////////////////////////////////////////////////////////
27324 
27325  Start of -include/epiworld/models/diffnet.hpp-
27326 
27329 
27330 
27331 #ifndef EPIWORLD_DIFFNET_H
27332 #define EPIWORLD_DIFFNET_H
27333 
27343 template<typename TSeq = EPI_DEFAULT_TSEQ>
27344 class ModelDiffNet : public epiworld::Model<TSeq>
27345 {
27346 private:
27347 public:
27348 
27349  ModelDiffNet() {};
27350 
27351  ModelDiffNet(
27352  ModelDiffNet<TSeq> & model,
27353  const std::string & innovation_name,
27354  epiworld_double prevalence,
27355  epiworld_double prob_adopt,
27356  bool normalize_exposure = true,
27357  double * agents_data = nullptr,
27358  size_t data_ncols = 0u,
27359  std::vector< size_t > data_cols = {},
27360  std::vector< double > params = {}
27361  );
27362 
27363  ModelDiffNet(
27364  const std::string & innovation_name,
27365  epiworld_double prevalence,
27366  epiworld_double prob_adopt,
27367  bool normalize_exposure = true,
27368  double * agents_data = nullptr,
27369  size_t data_ncols = 0u,
27370  std::vector< size_t > data_cols = {},
27371  std::vector< double > params = {}
27372  );
27373 
27374  static const int NONADOPTER = 0;
27375  static const int ADOPTER = 1;
27376 
27377  bool normalize_exposure = true;
27378  std::vector< size_t > data_cols;
27379  std::vector< double > params;
27380 };
27381 
27382 template<typename TSeq>
27383 inline ModelDiffNet<TSeq>::ModelDiffNet(
27384  ModelDiffNet<TSeq> & model,
27385  const std::string & innovation_name,
27386  epiworld_double prevalence,
27387  epiworld_double prob_adopt,
27388  bool normalize_exposure,
27389  double * agents_data,
27390  size_t data_ncols,
27391  std::vector< size_t > data_cols,
27392  std::vector< double > params
27393  )
27394 {
27395 
27396  // Adding additional parameters
27397  this->normalize_exposure = normalize_exposure;
27398  this->data_cols = data_cols;
27399  this->params = params;
27400 
27401  epiworld::UpdateFun<TSeq> update_non_adopters = [](
27402  epiworld::Agent<TSeq> * p, epiworld::Model<TSeq> * m
27403  ) -> void {
27404 
27405  // Measuring exposure
27406  // If the neighbor is infected, then proceed
27407  size_t nviruses = m->get_n_viruses();
27408  std::vector< Virus<TSeq>* > innovations(nviruses, {});
27409  std::vector< bool > stored(nviruses, false);
27410  std::vector< double > exposure(nviruses, 0.0);
27411 
27412  ModelDiffNet<TSeq> * diffmodel = dynamic_cast<ModelDiffNet<TSeq>*>(m);
27413 
27414  Agent<TSeq> & agent = *p;
27415 
27416  // For each one of the possible innovations, we have to compute
27417  // the adoption probability, which is a function of exposure
27418  for (auto & neighbor: agent.get_neighbors())
27419  {
27420 
27421  if (neighbor->get_state() == ModelDiffNet<TSeq>::ADOPTER)
27422  {
27423 
27424  auto & v = neighbor->get_virus();
27425 
27426  if (v == nullptr)
27427  continue;
27428 
27429  /* And it is a function of susceptibility_reduction as well */
27430  double p_i =
27431  (1.0 - agent.get_susceptibility_reduction(v, m)) *
27432  (1.0 - agent.get_transmission_reduction(v, m))
27433  ;
27434 
27435  size_t vid = v->get_id();
27436  if (!stored[vid])
27437  {
27438  stored[vid] = true;
27439  innovations[vid] = &(*v);
27440  }
27441  exposure[vid] += p_i;
27442 
27443 
27444  }
27445 
27446  }
27447 
27448  // Computing probability of adoption
27449  for (size_t i = 0u; i < nviruses; ++i)
27450  {
27451 
27452  if (diffmodel->normalize_exposure)
27453  exposure.at(i) /= agent.get_n_neighbors();
27454 
27455  for (auto & j: diffmodel->data_cols)
27456  exposure.at(i) += agent(j) * diffmodel->params.at(j);
27457 
27458  // Baseline probability of adoption
27459  double p = m->get_viruses()[i]->get_prob_infecting(m);
27460  exposure.at(i) += std::log(p) - std::log(1.0 - p);
27461 
27462  // Computing as log
27463  exposure.at(i) = 1.0/(1.0 + std::exp(-exposure.at(i)));
27464 
27465  }
27466 
27467  // Running the roulette to see is an innovation is adopted
27468  int which = roulette<int>(exposure, m);
27469 
27470  // No innovation was adopted
27471  if (which < 0)
27472  return;
27473 
27474  // Otherwise, it is adopted from any of the neighbors
27475  agent.set_virus(
27476  *innovations.at(which),
27477  m,
27478  ModelDiffNet::ADOPTER
27479  );
27480 
27481  return;
27482 
27483  };
27484 
27485  // Adding agents data
27486  model.set_agents_data(agents_data, data_ncols);
27487 
27488  // Adding statuses
27489  model.add_state("Non adopters", update_non_adopters);
27490  model.add_state("Adopters");
27491 
27492  // Adding parameters
27493  std::string parname = std::string("Prob. Adopting ") + innovation_name;
27494  model.add_param(prob_adopt, parname);
27495 
27496  // Preparing the virus -------------------------------------------
27497  epiworld::Virus<TSeq> innovation(innovation_name, prevalence, true);
27498  innovation.set_state(1,1,1);
27499 
27500  innovation.set_prob_infecting(&model(parname));
27501 
27502  model.add_virus(innovation);
27503 
27504  model.set_name(
27505  std::string("Diffusion of Innovations - ") + innovation_name);
27506 
27507  return;
27508 
27509 }
27510 
27511 template<typename TSeq>
27513  const std::string & innovation_name,
27514  epiworld_double prevalence,
27515  epiworld_double prob_adopt,
27516  bool normalize_exposure,
27517  double * agents_data,
27518  size_t data_ncols,
27519  std::vector< size_t > data_cols,
27520  std::vector< double > params
27521  )
27522 {
27523 
27525  *this,
27526  innovation_name,
27527  prevalence,
27528  prob_adopt,
27529  normalize_exposure,
27530  agents_data,
27531  data_ncols,
27532  data_cols,
27533  params
27534  );
27535 
27536  return;
27537 
27538 }
27539 
27540 #endif
27541 /*//////////////////////////////////////////////////////////////////////////////
27543 
27544  End of -include/epiworld/models/diffnet.hpp-
27545 
27548 
27549 
27550 /*//////////////////////////////////////////////////////////////////////////////
27552 
27553  Start of -include/epiworld/models/seirmixing.hpp-
27554 
27557 
27558 
27559 #ifndef EPIWORLD_MODELS_SEIRMIXING_HPP
27560 #define EPIWORLD_MODELS_SEIRMIXING_HPP
27561 
27562 #define MM(i, j, n) \
27563  j * n + i
27564 
27565 #if __cplusplus >= 202302L
27566  // C++23 or later
27567  #define GET_MODEL(model, output) \
27568  auto * output = dynamic_cast< ModelSEIRMixing<TSeq> * >( (model) ); \
27569  /*Using the [[assume(...)]] to avoid the compiler warning \
27570  if the standard is C++23 or later */ \
27571  [[assume((output) != nullptr)]];
27572 #else
27573  // C++17 or C++20
27574  #define GET_MODEL(model, output) \
27575  auto * output = dynamic_cast< ModelSEIRMixing<TSeq> * >( (model) ); \
27576  assert((output) != nullptr); // Use assert for runtime checks
27577 #endif
27578 
27583 template<typename TSeq = EPI_DEFAULT_TSEQ>
27584 class ModelSEIRMixing : public epiworld::Model<TSeq>
27585 {
27586 private:
27587 
27588  // Vector of vectors of infected agents
27589  std::vector< size_t > infected;
27590 
27591  // Number of infected agents in each group
27592  std::vector< size_t > n_infected_per_group;
27593 
27594  // Where the agents start in the `infected` vector
27595  std::vector< size_t > entity_indices;
27596 
27597  void update_infected_list();
27598  std::vector< size_t > sampled_agents;
27599  size_t sample_agents(
27600  epiworld::Agent<TSeq> * agent,
27601  std::vector< size_t > & sampled_agents
27602  );
27603  std::vector< double > adjusted_contact_rate;
27604  std::vector< double > contact_matrix;
27605 
27606  #ifdef EPI_DEBUG
27607  std::vector< int > sampled_sizes;
27608  #endif
27609 
27610 public:
27611 
27612  static const int SUSCEPTIBLE = 0;
27613  static const int EXPOSED = 1;
27614  static const int INFECTED = 2;
27615  static const int RECOVERED = 3;
27616 
27617  ModelSEIRMixing() {};
27618 
27634  ModelSEIRMixing<TSeq> & model,
27635  const std::string & vname,
27636  epiworld_fast_uint n,
27637  epiworld_double prevalence,
27638  epiworld_double contact_rate,
27639  epiworld_double transmission_rate,
27640  epiworld_double avg_incubation_days,
27641  epiworld_double recovery_rate,
27642  std::vector< double > contact_matrix
27643  );
27644 
27658  const std::string & vname,
27659  epiworld_fast_uint n,
27660  epiworld_double prevalence,
27661  epiworld_double contact_rate,
27662  epiworld_double transmission_rate,
27663  epiworld_double avg_incubation_days,
27664  epiworld_double recovery_rate,
27665  std::vector< double > contact_matrix
27666  );
27667 
27669  epiworld_fast_uint ndays,
27670  int seed = -1
27671  );
27672 
27673  void reset();
27674 
27675  Model<TSeq> * clone_ptr();
27676 
27683  std::vector< double > proportions_,
27684  std::vector< int > queue_ = {}
27685  );
27686 
27687  void set_contact_matrix(std::vector< double > cmat)
27688  {
27689  contact_matrix = cmat;
27690  return;
27691  };
27692 
27693 };
27694 
27695 template<typename TSeq>
27697 {
27698 
27699  auto & agents = Model<TSeq>::get_agents();
27700 
27701  std::fill(n_infected_per_group.begin(), n_infected_per_group.end(), 0u);
27702 
27703  for (auto & a : agents)
27704  {
27705 
27706  if (a.get_state() == ModelSEIRMixing<TSeq>::INFECTED)
27707  {
27708  if (a.get_n_entities() > 0u)
27709  {
27710  const auto & entity = a.get_entity(0u);
27711  infected[
27712  // Position of the group in the `infected` vector
27713  entity_indices[entity.get_id()] +
27714  // Position of the agent in the group
27715  n_infected_per_group[entity.get_id()]++
27716  ] = a.get_id();
27717 
27718  }
27719  }
27720 
27721  }
27722 
27723  return;
27724 
27725 }
27726 
27727 template<typename TSeq>
27729  epiworld::Agent<TSeq> * agent,
27730  std::vector< size_t > & sampled_agents
27731  )
27732 {
27733 
27734  size_t agent_group_id = agent->get_entity(0u).get_id();
27735  size_t ngroups = this->entities.size();
27736 
27737  int samp_id = 0;
27738  for (size_t g = 0; g < ngroups; ++g)
27739  {
27740 
27741  size_t group_size = n_infected_per_group[g];
27742 
27743  // How many from this entity?
27744  int nsamples = epiworld::Model<TSeq>::rbinom(
27745  group_size,
27746  adjusted_contact_rate[g] * contact_matrix[
27747  MM(agent_group_id, g, ngroups)
27748  ]
27749  );
27750 
27751  if (nsamples == 0)
27752  continue;
27753 
27754  // Sampling from the entity
27755  for (int s = 0; s < nsamples; ++s)
27756  {
27757 
27758  // Randomly selecting an agent
27759  int which = epiworld::Model<TSeq>::runif() * group_size;
27760 
27761  // Correcting overflow error
27762  if (which >= static_cast<int>(group_size))
27763  which = static_cast<int>(group_size) - 1;
27764 
27765  #ifdef EPI_DEBUG
27766  auto & a = this->population.at(infected.at(entity_indices[g] + which));
27767  #else
27768  auto & a = this->get_agent(infected[entity_indices[g] + which]);
27769  #endif
27770 
27771  #ifdef EPI_DEBUG
27772  if (a.get_state() != ModelSEIRMixing<TSeq>::INFECTED)
27773  throw std::logic_error(
27774  "The agent is not infected, but it should be."
27775  );
27776  #endif
27777 
27778  // Can't sample itself
27779  if (a.get_id() == agent->get_id())
27780  continue;
27781 
27782  sampled_agents[samp_id++] = a.get_id();
27783 
27784  }
27785 
27786  }
27787 
27788  return samp_id;
27789 
27790 }
27791 
27792 template<typename TSeq>
27794  epiworld_fast_uint ndays,
27795  int seed
27796 )
27797 {
27798 
27799  Model<TSeq>::run(ndays, seed);
27800 
27801  return *this;
27802 
27803 }
27804 
27805 template<typename TSeq>
27807 {
27808 
27810 
27811  // Checking contact matrix's rows add to one
27812  size_t nentities = this->entities.size();
27813  if (this->contact_matrix.size() != nentities*nentities)
27814  throw std::length_error(
27815  std::string("The contact matrix must be a square matrix of size ") +
27816  std::string("nentities x nentities. ") +
27817  std::to_string(this->contact_matrix.size()) +
27818  std::string(" != ") + std::to_string(nentities*nentities) +
27819  std::string(".")
27820  );
27821 
27822  for (size_t i = 0u; i < this->entities.size(); ++i)
27823  {
27824  double sum = 0.0;
27825  for (size_t j = 0u; j < this->entities.size(); ++j)
27826  {
27827  if (this->contact_matrix[MM(i, j, nentities)] < 0.0)
27828  throw std::range_error(
27829  std::string("The contact matrix must be non-negative. ") +
27830  std::to_string(this->contact_matrix[MM(i, j, nentities)]) +
27831  std::string(" < 0.")
27832  );
27833  sum += this->contact_matrix[MM(i, j, nentities)];
27834  }
27835  if (sum < 0.999 || sum > 1.001)
27836  throw std::range_error(
27837  std::string("The contact matrix must have rows that add to one. ") +
27838  std::to_string(sum) +
27839  std::string(" != 1.")
27840  );
27841  }
27842 
27843  // Do it the first time only
27844  sampled_agents.resize(Model<TSeq>::size());
27845 
27846  // We only do it once
27847  n_infected_per_group.resize(this->entities.size(), 0u);
27848  std::fill(n_infected_per_group.begin(), n_infected_per_group.end(), 0u);
27849 
27850  // We are assuming one agent per entity
27851  infected.resize(Model<TSeq>::size());
27852  std::fill(infected.begin(), infected.end(), 0u);
27853 
27854  // This will say when do the groups start in the `infected` vector
27855  entity_indices.resize(this->entities.size(), 0u);
27856  std::fill(entity_indices.begin(), entity_indices.end(), 0u);
27857  for (size_t i = 1u; i < this->entities.size(); ++i)
27858  {
27859 
27860  entity_indices[i] +=
27861  this->entities[i - 1].size() +
27862  entity_indices[i - 1]
27863  ;
27864 
27865  }
27866 
27867  // Adjusting contact rate
27868  adjusted_contact_rate.clear();
27869  adjusted_contact_rate.resize(this->entities.size(), 0.0);
27870 
27871  for (size_t i = 0u; i < this->entities.size(); ++i)
27872  {
27873 
27874  adjusted_contact_rate[i] =
27875  Model<TSeq>::get_param("Contact rate") /
27876  static_cast< epiworld_double > (this->get_entity(i).size());
27877 
27878 
27879  // Possibly correcting for a small number of agents
27880  if (adjusted_contact_rate[i] > 1.0)
27881  adjusted_contact_rate[i] = 1.0;
27882 
27883  }
27884 
27885  this->update_infected_list();
27886 
27887  return;
27888 
27889 }
27890 
27891 template<typename TSeq>
27893 {
27894 
27896  *dynamic_cast<const ModelSEIRMixing<TSeq>*>(this)
27897  );
27898 
27899  #if __cplusplus >= 202302L
27900  // C++23 or later
27901  [[assume(ptr != nullptr)]];
27902  #else
27903  // C++17 or C++20
27904  assert(ptr != nullptr); // Use assert for runtime checks
27905  #endif
27906 
27907  return dynamic_cast< Model<TSeq> *>(ptr);
27908 
27909 }
27910 
27911 
27922 template<typename TSeq>
27924  ModelSEIRMixing<TSeq> & model,
27925  const std::string & vname,
27926  epiworld_fast_uint n,
27927  epiworld_double prevalence,
27928  epiworld_double contact_rate,
27929  epiworld_double transmission_rate,
27930  epiworld_double avg_incubation_days,
27931  epiworld_double recovery_rate,
27932  std::vector< double > contact_matrix
27933  )
27934 {
27935 
27936  // Setting up the contact matrix
27937  this->contact_matrix = contact_matrix;
27938 
27939  epiworld::UpdateFun<TSeq> update_susceptible = [](
27941  ) -> void
27942  {
27943 
27944  if (p->get_n_entities() == 0)
27945  return;
27946 
27947  // Downcasting to retrieve the sampler attached to the
27948  // class
27949  GET_MODEL(m, m_down);
27950 
27951  size_t ndraws = m_down->sample_agents(p, m_down->sampled_agents);
27952 
27953  #ifdef EPI_DEBUG
27954  m_down->sampled_sizes.push_back(static_cast<int>(ndraws));
27955  #endif
27956 
27957  if (ndraws == 0u)
27958  return;
27959 
27960  // Drawing from the set
27961  int nviruses_tmp = 0;
27962  for (size_t n = 0u; n < ndraws; ++n)
27963  {
27964 
27965  auto & neighbor = m->get_agent(m_down->sampled_agents[n]);
27966 
27967  auto & v = neighbor.get_virus();
27968 
27969  #ifdef EPI_DEBUG
27970  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
27971  throw std::logic_error(
27972  "Trying to add an extra element to a temporal array outside of the range."
27973  );
27974  #endif
27975 
27976  /* And it is a function of susceptibility_reduction as well */
27977  m->array_double_tmp[nviruses_tmp] =
27978  (1.0 - p->get_susceptibility_reduction(v, m)) *
27979  v->get_prob_infecting(m) *
27980  (1.0 - neighbor.get_transmission_reduction(v, m))
27981  ;
27982 
27983  m->array_virus_tmp[nviruses_tmp++] = &(*v);
27984 
27985  }
27986 
27987  // Running the roulette
27988  int which = roulette(nviruses_tmp, m);
27989 
27990  if (which < 0)
27991  return;
27992 
27993  p->set_virus(
27994  *m->array_virus_tmp[which],
27995  m,
27997  );
27998 
27999  return;
28000 
28001  };
28002 
28003  epiworld::UpdateFun<TSeq> update_exposed_and_infected = [](
28005  ) -> void {
28006 
28007  auto state = p->get_state();
28008 
28009  if (state == ModelSEIRMixing<TSeq>::EXPOSED)
28010  {
28011 
28012  // Getting the virus
28013  auto & v = p->get_virus();
28014 
28015  // Does the agent become infected?
28016  if (m->runif() < 1.0/(v->get_incubation(m)))
28017  {
28018 
28019  p->change_state(m, ModelSEIRMixing<TSeq>::INFECTED);
28020  return;
28021 
28022  }
28023 
28024 
28025  } else if (state == ModelSEIRMixing<TSeq>::INFECTED)
28026  {
28027 
28028 
28029  // Odd: Die, Even: Recover
28030  epiworld_fast_uint n_events = 0u;
28031  const auto & v = p->get_virus();
28032 
28033  // Recover
28034  m->array_double_tmp[n_events++] =
28035  1.0 - (1.0 - v->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(v, m));
28036 
28037  #ifdef EPI_DEBUG
28038  if (n_events == 0u)
28039  {
28040  printf_epiworld(
28041  "[epi-debug] agent %i has 0 possible events!!\n",
28042  static_cast<int>(p->get_id())
28043  );
28044  throw std::logic_error("Zero events in exposed.");
28045  }
28046  #else
28047  if (n_events == 0u)
28048  return;
28049  #endif
28050 
28051 
28052  // Running the roulette
28053  int which = roulette(n_events, m);
28054 
28055  if (which < 0)
28056  return;
28057 
28058  // Which roulette happen?
28059  p->rm_virus(m);
28060 
28061  return ;
28062 
28063  } else
28064  throw std::logic_error("This function can only be applied to exposed or infected individuals. (SEIR)") ;
28065 
28066  return;
28067 
28068  };
28069 
28070  // Setting up parameters
28071  model.add_param(contact_rate, "Contact rate");
28072  model.add_param(transmission_rate, "Prob. Transmission");
28073  model.add_param(recovery_rate, "Prob. Recovery");
28074  model.add_param(avg_incubation_days, "Avg. Incubation days");
28075 
28076  // state
28077  model.add_state("Susceptible", update_susceptible);
28078  model.add_state("Exposed", update_exposed_and_infected);
28079  model.add_state("Infected", update_exposed_and_infected);
28080  model.add_state("Recovered");
28081 
28082  // Global function
28083  epiworld::GlobalFun<TSeq> update = [](epiworld::Model<TSeq> * m) -> void
28084  {
28085 
28086  GET_MODEL(m, m_down);
28087 
28088  m_down->update_infected_list();
28089 
28090  return;
28091 
28092  };
28093 
28094  model.add_globalevent(update, "Update infected individuals");
28095 
28096 
28097  // Preparing the virus -------------------------------------------
28098  epiworld::Virus<TSeq> virus(vname, prevalence, true);
28099  virus.set_state(
28103  );
28104 
28105  virus.set_prob_infecting(&model("Prob. Transmission"));
28106  virus.set_prob_recovery(&model("Prob. Recovery"));
28107  virus.set_incubation(&model("Avg. Incubation days"));
28108 
28109  model.add_virus(virus);
28110 
28111  model.queuing_off(); // No queuing need
28112 
28113  // Adding the empty population
28114  model.agents_empty_graph(n);
28115 
28116  model.set_name("Susceptible-Exposed-Infected-Removed (SEIR) with Mixing");
28117 
28118  return;
28119 
28120 }
28121 
28122 template<typename TSeq>
28124  const std::string & vname,
28125  epiworld_fast_uint n,
28126  epiworld_double prevalence,
28127  epiworld_double contact_rate,
28128  epiworld_double transmission_rate,
28129  epiworld_double avg_incubation_days,
28130  epiworld_double recovery_rate,
28131  std::vector< double > contact_matrix
28132  )
28133 {
28134 
28135  this->contact_matrix = contact_matrix;
28136 
28138  *this,
28139  vname,
28140  n,
28141  prevalence,
28142  contact_rate,
28143  transmission_rate,
28144  avg_incubation_days,
28145  recovery_rate,
28146  contact_matrix
28147  );
28148 
28149  return;
28150 
28151 }
28152 
28153 template<typename TSeq>
28155  std::vector< double > proportions_,
28156  std::vector< int > /* queue_ */
28157 )
28158 {
28159 
28161  create_init_function_seir<TSeq>(proportions_)
28162  ;
28163 
28164  return *this;
28165 
28166 }
28167 #undef MM
28168 #undef GET_MODEL
28169 #endif
28170 /*//////////////////////////////////////////////////////////////////////////////
28172 
28173  End of -include/epiworld/models/seirmixing.hpp-
28174 
28177 
28178 
28179 /*//////////////////////////////////////////////////////////////////////////////
28181 
28182  Start of -include/epiworld/models/sirmixing.hpp-
28183 
28186 
28187 
28188 #ifndef EPIWORLD_MODELS_SIRMIXING_HPP
28189 #define EPIWORLD_MODELS_SIRMIXING_HPP
28190 
28191 #if __cplusplus >= 202302L
28192  // C++23 or later
28193  #define GET_MODEL(model, output) \
28194  auto * output = dynamic_cast< ModelSIRMixing<TSeq> * >( (model) ); \
28195  /*Using the [[assume(...)]] to avoid the compiler warning \
28196  if the standard is C++23 or later */ \
28197  [[assume((output) != nullptr)]];
28198 #else
28199  // C++17 or C++20
28200  #define GET_MODEL(model, output) \
28201  auto * output = dynamic_cast< ModelSIRMixing<TSeq> * >( (model) ); \
28202  assert((output) != nullptr); // Use assert for runtime checks
28203 #endif
28204 
28209 template<typename TSeq = EPI_DEFAULT_TSEQ>
28210 class ModelSIRMixing : public epiworld::Model<TSeq>
28211 {
28212 private:
28213 
28214  // Vector of infected agents
28215  std::vector< size_t > infected;
28216  size_t n_infected;
28217 
28218  // Number of infected agents in each group
28219  std::vector< size_t > n_infected_per_group;
28220 
28221  // Where the agents start in the `infected` vector
28222  std::vector< size_t > entity_indices;
28223 
28224  void update_infected_list();
28225  std::vector< size_t > sampled_agents;
28226  size_t sample_agents(
28227  epiworld::Agent<TSeq> * agent,
28228  std::vector< size_t > & sampled_agents
28229  );
28230 
28231  std::vector< double > adjusted_contact_rate;
28232  std::vector< double > contact_matrix;
28233 
28234  size_t index(size_t i, size_t j, size_t n) {
28235  return j * n + i;
28236  }
28237 
28238 public:
28239 
28240  static const int SUSCEPTIBLE = 0;
28241  static const int INFECTED = 1;
28242  static const int RECOVERED = 2;
28243 
28244  ModelSIRMixing() {};
28245 
28259  ModelSIRMixing<TSeq> & model,
28260  const std::string & vname,
28261  epiworld_fast_uint n,
28262  epiworld_double prevalence,
28263  epiworld_double contact_rate,
28264  epiworld_double transmission_rate,
28265  epiworld_double recovery_rate,
28266  std::vector< double > contact_matrix
28267  );
28268 
28281  const std::string & vname,
28282  epiworld_fast_uint n,
28283  epiworld_double prevalence,
28284  epiworld_double contact_rate,
28285  epiworld_double transmission_rate,
28286  epiworld_double recovery_rate,
28287  std::vector< double > contact_matrix
28288  );
28289 
28291  epiworld_fast_uint ndays,
28292  int seed = -1
28293  );
28294 
28295  void reset();
28296 
28297  Model<TSeq> * clone_ptr();
28298 
28305  std::vector< double > proportions_,
28306  std::vector< int > queue_ = {}
28307  );
28308 
28309  size_t get_n_infected(size_t group) const
28310  {
28311  return n_infected_per_group[group];
28312  }
28313 
28314  void set_contact_matrix(std::vector< double > cmat)
28315  {
28316  contact_matrix = cmat;
28317  return;
28318  };
28319 
28320 };
28321 
28322 template<typename TSeq>
28324 {
28325  auto & agents = Model<TSeq>::get_agents();
28326 
28327  std::fill(n_infected_per_group.begin(), n_infected_per_group.end(), 0u);
28328  n_infected = 0;
28329 
28330  for (auto & a : agents)
28331  {
28332  if (a.get_state() == ModelSIRMixing<TSeq>::INFECTED)
28333  {
28334  if (a.get_n_entities() > 0u)
28335  {
28336  const auto & entity = a.get_entity(0u);
28337  infected[
28338  // Position of the group in the `infected` vector
28339  entity_indices[entity.get_id()] +
28340  // Position of the agent in the group
28341  n_infected_per_group[entity.get_id()]++
28342  ] = a.get_id();
28343 
28344  // Incrementing the overall counter
28345  n_infected++;
28346  }
28347  }
28348  }
28349 
28350  return;
28351 }
28352 
28353 template<typename TSeq>
28355  epiworld::Agent<TSeq> * agent,
28356  std::vector< size_t > & sampled_agents
28357  )
28358 {
28359 
28360  size_t agent_group_id = agent->get_entity(0u).get_id();
28361  size_t ngroups = this->entities.size();
28362 
28363  int samp_id = 0;
28364  for (size_t g = 0; g < ngroups; ++g)
28365  {
28366 
28367  size_t group_size = n_infected_per_group[g];
28368 
28369  // How many from this entity?
28370  int nsamples = epiworld::Model<TSeq>::rbinom(
28371  group_size,
28372  adjusted_contact_rate[g] * contact_matrix[
28373  index(agent_group_id, g, ngroups)
28374  ]
28375  );
28376 
28377  if (nsamples == 0)
28378  continue;
28379 
28380  // Sampling from the entity
28381  for (int s = 0; s < nsamples; ++s)
28382  {
28383 
28384  // Randomly selecting an agent
28385  int which = epiworld::Model<TSeq>::runif() * group_size;
28386 
28387  // Correcting overflow error
28388  if (which >= static_cast<int>(group_size))
28389  which = static_cast<int>(group_size) - 1;
28390 
28391  #ifdef EPI_DEBUG
28392  auto & a = this->population.at(infected.at(entity_indices[g] + which));
28393  #else
28394  auto & a = this->get_agent(infected[entity_indices[g] + which]);
28395  #endif
28396 
28397  #ifdef EPI_DEBUG
28398  if (a.get_state() != ModelSIRMixing<TSeq>::INFECTED)
28399  throw std::logic_error(
28400  "The agent is not infected, but it should be."
28401  );
28402  #endif
28403 
28404  // Can't sample itself
28405  if (a.get_id() == agent->get_id())
28406  continue;
28407 
28408  sampled_agents[samp_id++] = a.get_id();
28409 
28410  }
28411 
28412  }
28413 
28414  return samp_id;
28415 
28416 }
28417 
28418 template<typename TSeq>
28420  epiworld_fast_uint ndays,
28421  int seed
28422 )
28423 {
28424 
28425  Model<TSeq>::run(ndays, seed);
28426  return *this;
28427 
28428 }
28429 
28430 template<typename TSeq>
28432 {
28433 
28435 
28436  // Checking contact matrix's rows add to one
28437  size_t nentities = this->entities.size();
28438  if (this->contact_matrix.size() != nentities*nentities)
28439  throw std::length_error(
28440  std::string("The contact matrix must be a square matrix of size ") +
28441  std::string("nentities x nentities. ") +
28442  std::to_string(this->contact_matrix.size()) +
28443  std::string(" != ") + std::to_string(nentities*nentities) +
28444  std::string(".")
28445  );
28446 
28447  for (size_t i = 0u; i < this->entities.size(); ++i)
28448  {
28449  double sum = 0.0;
28450  for (size_t j = 0u; j < this->entities.size(); ++j)
28451  {
28452  if (this->contact_matrix[index(i, j, nentities)] < 0.0)
28453  throw std::range_error(
28454  std::string("The contact matrix must be non-negative. ") +
28455  std::to_string(this->contact_matrix[index(i, j, nentities)]) +
28456  std::string(" < 0.")
28457  );
28458  sum += this->contact_matrix[index(i, j, nentities)];
28459  }
28460  if (sum < 0.999 || sum > 1.001)
28461  throw std::range_error(
28462  std::string("The contact matrix must have rows that add to one. ") +
28463  std::to_string(sum) +
28464  std::string(" != 1.")
28465  );
28466  }
28467 
28468  // Do it the first time only
28469  sampled_agents.resize(Model<TSeq>::size());
28470 
28471  // We only do it once
28472  n_infected_per_group.resize(this->entities.size(), 0u);
28473  std::fill(n_infected_per_group.begin(), n_infected_per_group.end(), 0u);
28474 
28475  // We are assuming one agent per entity
28476  infected.resize(Model<TSeq>::size());
28477  std::fill(infected.begin(), infected.end(), 0u);
28478 
28479  // This will say when do the groups start in the `infected` vector
28480  entity_indices.resize(this->entities.size(), 0u);
28481  std::fill(entity_indices.begin(), entity_indices.end(), 0u);
28482  for (size_t i = 1u; i < this->entities.size(); ++i)
28483  {
28484  entity_indices[i] +=
28485  this->entities[i - 1].size() +
28486  entity_indices[i - 1]
28487  ;
28488  }
28489 
28490  // Adjusting contact rate
28491  adjusted_contact_rate.clear();
28492  adjusted_contact_rate.resize(this->entities.size(), 0.0);
28493 
28494  for (size_t i = 0u; i < this->entities.size(); ++i)
28495  {
28496  adjusted_contact_rate[i] =
28497  Model<TSeq>::get_param("Contact rate") /
28498  static_cast< epiworld_double > (this->get_entity(i).size());
28499 
28500  // Possibly correcting for a small number of agents
28501  if (adjusted_contact_rate[i] > 1.0)
28502  adjusted_contact_rate[i] = 1.0;
28503  }
28504 
28505  this->update_infected_list();
28506 
28507  return;
28508 }
28509 
28510 template<typename TSeq>
28512 {
28513 
28515  *dynamic_cast<const ModelSIRMixing<TSeq>*>(this)
28516  );
28517 
28518  return dynamic_cast< Model<TSeq> *>(ptr);
28519 
28520 }
28521 
28522 
28533 template<typename TSeq>
28535  ModelSIRMixing<TSeq> & model,
28536  const std::string & vname,
28537  epiworld_fast_uint n,
28538  epiworld_double prevalence,
28539  epiworld_double contact_rate,
28540  epiworld_double transmission_rate,
28541  epiworld_double recovery_rate,
28542  std::vector< double > contact_matrix
28543  )
28544 {
28545 
28546  // Setting up the contact matrix
28547  this->contact_matrix = contact_matrix;
28548 
28549  epiworld::UpdateFun<TSeq> update_susceptible = [](
28551  ) -> void
28552  {
28553 
28554  if (p->get_n_entities() == 0)
28555  return;
28556 
28557  // Downcasting to retrieve the sampler attached to the
28558  // class
28559  GET_MODEL(m, m_down);
28560 
28561  size_t ndraws = m_down->sample_agents(p, m_down->sampled_agents);
28562 
28563  if (ndraws == 0u)
28564  return;
28565 
28566 
28567  // Drawing from the set
28568  int nviruses_tmp = 0;
28569  for (size_t n = 0u; n < ndraws; ++n)
28570  {
28571 
28572  auto & neighbor = m->get_agent(m_down->sampled_agents[n]);
28573 
28574  auto & v = neighbor.get_virus();
28575 
28576  #ifdef EPI_DEBUG
28577  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
28578  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
28579  #endif
28580 
28581  /* And it is a function of susceptibility_reduction as well */
28582  m->array_double_tmp[nviruses_tmp] =
28583  (1.0 - p->get_susceptibility_reduction(v, m)) *
28584  v->get_prob_infecting(m) *
28585  (1.0 - neighbor.get_transmission_reduction(v, m))
28586  ;
28587 
28588  m->array_virus_tmp[nviruses_tmp++] = &(*v);
28589 
28590  }
28591 
28592  // Running the roulette
28593  int which = roulette(nviruses_tmp, m);
28594 
28595  if (which < 0)
28596  return;
28597 
28598  p->set_virus(
28599  *m->array_virus_tmp[which],
28600  m,
28602  );
28603 
28604  return;
28605 
28606  };
28607 
28608  epiworld::UpdateFun<TSeq> update_infected = [](
28610  ) -> void {
28611 
28612  auto state = p->get_state();
28613 
28614  if (state == ModelSIRMixing<TSeq>::INFECTED)
28615  {
28616 
28617 
28618  // Odd: Die, Even: Recover
28619  epiworld_fast_uint n_events = 0u;
28620  const auto & v = p->get_virus();
28621 
28622  // Recover
28623  m->array_double_tmp[n_events++] =
28624  1.0 - (1.0 - v->get_prob_recovery(m)) * (1.0 - p->get_recovery_enhancer(v, m));
28625 
28626  #ifdef EPI_DEBUG
28627  if (n_events == 0u)
28628  {
28629  printf_epiworld(
28630  "[epi-debug] agent %i has 0 possible events!!\n",
28631  static_cast<int>(p->get_id())
28632  );
28633  throw std::logic_error("Zero events in infected.");
28634  }
28635  #else
28636  if (n_events == 0u)
28637  return;
28638  #endif
28639 
28640 
28641  // Running the roulette
28642  int which = roulette(n_events, m);
28643 
28644  if (which < 0)
28645  return;
28646 
28647  // Which roulette happen?
28648  p->rm_virus(m);
28649 
28650  return ;
28651 
28652  } else
28653  throw std::logic_error("This function can only be applied to infected individuals. (SIR)") ;
28654 
28655  return;
28656 
28657  };
28658 
28659  // Setting up parameters
28660  model.add_param(contact_rate, "Contact rate");
28661  model.add_param(transmission_rate, "Prob. Transmission");
28662  model.add_param(recovery_rate, "Prob. Recovery");
28663 
28664  // state
28665  model.add_state("Susceptible", update_susceptible);
28666  model.add_state("Infected", update_infected);
28667  model.add_state("Recovered");
28668 
28669  // Global function
28670  epiworld::GlobalFun<TSeq> update = [](epiworld::Model<TSeq> * m) -> void
28671  {
28672 
28673  GET_MODEL(m, m_down);
28674 
28675  m_down->update_infected_list();
28676 
28677  return;
28678 
28679  };
28680 
28681  model.add_globalevent(update, "Update infected individuals");
28682 
28683 
28684  // Preparing the virus -------------------------------------------
28685  epiworld::Virus<TSeq> virus(vname, prevalence, true);
28686  virus.set_state(
28690  );
28691 
28692  virus.set_prob_infecting(&model("Prob. Transmission"));
28693  virus.set_prob_recovery(&model("Prob. Recovery"));
28694 
28695  model.add_virus(virus);
28696 
28697  model.queuing_off(); // No queuing need
28698 
28699  // Adding the empty population
28700  model.agents_empty_graph(n);
28701 
28702  model.set_name("Susceptible-Infected-Removed (SIR) with Mixing");
28703 
28704  return;
28705 
28706 }
28707 
28708 template<typename TSeq>
28710  const std::string & vname,
28711  epiworld_fast_uint n,
28712  epiworld_double prevalence,
28713  epiworld_double contact_rate,
28714  epiworld_double transmission_rate,
28715  epiworld_double recovery_rate,
28716  std::vector< double > contact_matrix
28717  )
28718 {
28719 
28720  this->contact_matrix = contact_matrix;
28721 
28723  *this,
28724  vname,
28725  n,
28726  prevalence,
28727  contact_rate,
28728  transmission_rate,
28729  recovery_rate,
28730  contact_matrix
28731  );
28732 
28733  return;
28734 
28735 }
28736 
28737 template<typename TSeq>
28739  std::vector< double > proportions_,
28740  std::vector< int > /* queue_ */
28741 )
28742 {
28743 
28745  create_init_function_sir<TSeq>(proportions_)
28746  ;
28747 
28748  return *this;
28749 
28750 }
28751 
28752 #undef GET_MODEL
28753 #endif
28754 /*//////////////////////////////////////////////////////////////////////////////
28756 
28757  End of -include/epiworld/models/sirmixing.hpp-
28758 
28761 
28762 
28763 /*//////////////////////////////////////////////////////////////////////////////
28765 
28766  Start of -include/epiworld/models/measlesschool.hpp-
28767 
28770 
28771 
28772 #ifndef MEASLESQUARANTINE_HPP
28773 #define MEASLESQUARANTINE_HPP
28774 
28775 #if __cplusplus >= 202302L
28776  // C++23 or later
28777  #define GET_MODEL(model, output) \
28778  ModelMeaslesSchool<TSeq> * output = \
28779  dynamic_cast<ModelMeaslesSchool<TSeq> *>(model); \
28780  [[assume(output != nullptr)]];
28781 #else
28782  // C++17 or C++20
28783  #define GET_MODEL(model, output) \
28784  ModelMeaslesSchool<TSeq> * output = \
28785  dynamic_cast<ModelMeaslesSchool<TSeq> *>(model); \
28786  assert(output != nullptr); // Use assert for runtime checks
28787 #endif
28788 
28789 #define LOCAL_UPDATE_FUN(name) \
28790  template<typename TSeq> \
28791  inline void ModelMeaslesSchool<TSeq>:: name \
28792  (epiworld::Agent<TSeq> * p, epiworld::Model<TSeq> * m)
28793 
28794 #define SAMPLE_FROM_PROBS(n, ans) \
28795  size_t ans; \
28796  epiworld_double p_total = m->runif(); \
28797  for (ans = 0u; ans < n; ++ans) \
28798  { \
28799  if (p_total < m->array_double_tmp[ans]) \
28800  break; \
28801  m->array_double_tmp[ans + 1] += m->array_double_tmp[ans]; \
28802  }
28803 
28819 template<typename TSeq = EPI_DEFAULT_TSEQ>
28820 class ModelMeaslesSchool: public Model<TSeq> {
28821 
28822 private:
28823 
28828  static void m_update_susceptible(Agent<TSeq> * p, Model<TSeq> * m);
28829  static void m_update_exposed(Agent<TSeq> * p, Model<TSeq> * m);
28830  static void m_update_prodromal(Agent<TSeq> * p, Model<TSeq> * m);
28831  static void m_update_rash(Agent<TSeq> * p, Model<TSeq> * m);
28832  static void m_update_isolated(Agent<TSeq> * p, Model<TSeq> * m);
28833  static void m_update_isolated_recovered(Agent<TSeq> * p, Model<TSeq> * m);
28834  static void m_update_q_exposed(Agent<TSeq> * p, Model<TSeq> * m);
28835  static void m_update_q_susceptible(Agent<TSeq> * p, Model<TSeq> * m);
28836  static void m_update_q_prodromal(Agent<TSeq> * p, Model<TSeq> * m);
28837  static void m_update_q_recovered(Agent<TSeq> * p, Model<TSeq> * m);
28838  static void m_update_hospitalized(Agent<TSeq> * p, Model<TSeq> * m);
28840 
28846  static void m_update_model(Model<TSeq> * m);
28847 
28848 public:
28849 
28850  static constexpr epiworld_fast_uint SUSCEPTIBLE = 0u;
28851  static constexpr epiworld_fast_uint EXPOSED = 1u;
28852  static constexpr epiworld_fast_uint PRODROMAL = 2u;
28853  static constexpr epiworld_fast_uint RASH = 3u;
28854  static constexpr epiworld_fast_uint ISOLATED = 4u;
28855  static constexpr epiworld_fast_uint ISOLATED_RECOVERED = 5u;
28856  static constexpr epiworld_fast_uint DETECTED_HOSPITALIZED = 6u;
28857  static constexpr epiworld_fast_uint QUARANTINED_EXPOSED = 7u;
28858  static constexpr epiworld_fast_uint QUARANTINED_SUSCEPTIBLE = 8u;
28859  static constexpr epiworld_fast_uint QUARANTINED_PRODROMAL = 9u;
28860  static constexpr epiworld_fast_uint QUARANTINED_RECOVERED = 10u;
28861  static constexpr epiworld_fast_uint HOSPITALIZED = 11u;
28862  static constexpr epiworld_fast_uint RECOVERED = 12u;
28863 
28864  // Default constructor
28865  ModelMeaslesSchool() {};
28866 
28886  ModelMeaslesSchool(
28887  ModelMeaslesSchool<TSeq> & model,
28888  epiworld_fast_uint n,
28889  epiworld_fast_uint n_exposed,
28890  // Disease parameters
28891  epiworld_double contact_rate,
28892  epiworld_double transmission_rate,
28893  epiworld_double vax_efficacy,
28894  epiworld_double vax_reduction_recovery_rate,
28895  epiworld_double incubation_period,
28896  epiworld_double prodromal_period,
28897  epiworld_double rash_period,
28898  epiworld_double days_undetected,
28899  epiworld_double hospitalization_rate,
28900  epiworld_double hospitalization_period,
28901  // Policy parameters
28902  epiworld_double prop_vaccinated,
28903  epiworld_fast_int quarantine_period,
28904  epiworld_double quarantine_willingness,
28905  epiworld_fast_int isolation_period
28906  );
28907 
28908  ModelMeaslesSchool(
28909  epiworld_fast_uint n,
28910  epiworld_fast_uint n_exposed,
28911  // Disease parameters
28912  epiworld_double contact_rate,
28913  epiworld_double transmission_rate,
28914  epiworld_double vax_efficacy,
28915  epiworld_double vax_reduction_recovery_rate,
28916  epiworld_double incubation_period,
28917  epiworld_double prodromal_period,
28918  epiworld_double rash_period,
28919  epiworld_double days_undetected,
28920  epiworld_double hospitalization_rate,
28921  epiworld_double hospitalization_period,
28922  // Policy parameters
28923  epiworld_double prop_vaccinated,
28924  epiworld_fast_int quarantine_period,
28925  epiworld_double quarantine_willingness,
28926  epiworld_fast_int isolation_period
28927  );
28929 
28930  std::vector<Agent<TSeq> *> infectious; ///< Agents infectious for contact
28931 
28932  bool system_quarantine_triggered = false;
28933 
28934  std::vector< int > day_flagged; ///< Either detected or started quarantine
28935  std::vector< int > day_rash_onset; ///< Day of rash onset
28936 
28955  void quarantine_agents();
28956 
28957  void reset();
28958  void update_infectious();
28959 
28960  Model<TSeq> * clone_ptr();
28961 
28962 };
28963 
28964 template<typename TSeq>
28965 inline void ModelMeaslesSchool<TSeq>::quarantine_agents() {
28966 
28967  // Iterating through the new cases
28968  if (!system_quarantine_triggered)
28969  return;
28970 
28971  // Quarantine and isolation can be shut off if negative
28972  if (
28973  (this->par("Quarantine period") < 0) &&
28974  (this->par("Isolation period") < 0)
28975  )
28976  return;
28977 
28978  // Capturing the days that matter and the probability of success
28979  epiworld_double willingness = this->par("Quarantine willingness");
28980 
28981  // Iterating through the
28982  for (size_t i = 0u; i < this->size(); ++i) {
28983 
28984  auto agent_state = this->get_agent(i).get_state();
28985 
28986  // Already quarantined or isolated
28987  if (agent_state >= RASH)
28988  continue;
28989 
28990  // If the agent has a vaccine, then no need for quarantine
28991  if (this->get_agent(i).get_n_tools() != 0u)
28992  continue;
28993 
28994  // Quarantine will depend on the willingness of the agent
28995  // to be quarantined. If negative, then quarantine never happens.
28996  if (
28997  (this->par("Quarantine period") >= 0) &&
28998  (this->runif() < willingness)
28999  )
29000  {
29001 
29002  if (agent_state == SUSCEPTIBLE)
29003  this->get_agent(i).change_state(this, QUARANTINED_SUSCEPTIBLE);
29004  else if (agent_state == EXPOSED)
29005  this->get_agent(i).change_state(this, QUARANTINED_EXPOSED);
29006  else if (agent_state == PRODROMAL)
29007  this->get_agent(i).change_state(this, QUARANTINED_PRODROMAL);
29008 
29009  // And we add the day of quarantine
29010  this->day_flagged[i] = this->today();
29011 
29012  }
29013 
29014  }
29015 
29016  // Setting the quarantine process off
29017  this->system_quarantine_triggered = false;
29018 
29019  return;
29020 
29021 }
29022 
29023 
29024 template<typename TSeq>
29025 inline void ModelMeaslesSchool<TSeq>::m_update_model(Model<TSeq> * m) {
29026 
29027  GET_MODEL(m, model);
29028  model->quarantine_agents();
29029  model->events_run();
29030  model->update_infectious();
29031  return;
29032 
29033 }
29034 
29035 template<typename TSeq>
29036 inline void ModelMeaslesSchool<TSeq>::reset() {
29037 
29038  Model<TSeq>::reset();
29039 
29040  this->system_quarantine_triggered = false;
29041 
29042  this->day_flagged.resize(this->size(), 0);
29043  std::fill(
29044  day_flagged.begin(),
29045  day_flagged.end(),
29046  0);
29047 
29048  this->day_rash_onset.resize(this->size(), 0);
29049  std::fill(
29050  day_rash_onset.begin(),
29051  day_rash_onset.end(),
29052  0);
29053 
29054  this->m_update_model(dynamic_cast<Model<TSeq>*>(this));
29055  return;
29056 
29057 }
29058 
29059 template<typename TSeq>
29060 inline void ModelMeaslesSchool<TSeq>::update_infectious() {
29061 
29062  #ifdef EPI_DEBUG
29063  // All agents with state >= EXPOSED should have a virus
29064  for (auto & agent: this->get_agents())
29065  {
29066  auto s = agent.get_state();
29067  if (IN(s, {EXPOSED, PRODROMAL, RASH, ISOLATED, DETECTED_HOSPITALIZED, QUARANTINED_EXPOSED, QUARANTINED_PRODROMAL, HOSPITALIZED}))
29068  {
29069  if (agent.get_virus() == nullptr)
29070  throw std::logic_error("The agent has no virus.");
29071  }
29072  }
29073  #endif
29074 
29075  this->infectious.clear();
29076  int n_available = 0;
29077  for (auto & agent: this->get_agents())
29078  {
29079  const auto & s = agent.get_state();
29080  if (s == PRODROMAL)
29081  this->infectious.push_back(&agent);
29082 
29083  if (s < RASH)
29084  ++n_available;
29085 
29086  }
29087 
29088  // Assumes fixed contact rate throughout the simulation
29089  double p_contact = this->par("Contact rate")/
29090  static_cast< epiworld_double >(n_available);
29091 
29092  this->set_rand_binom(
29093  static_cast<int>(this->infectious.size()),
29094  p_contact > 1.0 ? 1.0 : p_contact
29095  );
29096 
29097 }
29098 
29099 template<typename TSeq>
29100 inline Model<TSeq> * ModelMeaslesSchool<TSeq>::clone_ptr()
29101 {
29102 
29103  ModelMeaslesSchool<TSeq> * ptr = new ModelMeaslesSchool<TSeq>(
29104  *dynamic_cast<const ModelMeaslesSchool<TSeq>*>(this)
29105  );
29106 
29107  return dynamic_cast< Model<TSeq> *>(ptr);
29108 
29109 }
29110 
29111 LOCAL_UPDATE_FUN(m_update_susceptible) {
29112 
29113  // How many contacts to draw
29114  int ndraw = m->rbinom();
29115 
29116  if (ndraw == 0)
29117  return;
29118 
29119  GET_MODEL(m, model);
29120  size_t n_infectious = model->infectious.size();
29121 
29122  if (n_infectious == 0)
29123  return;
29124 
29125  // Drawing from the set
29126  int nviruses_tmp = 0;
29127  int i = 0;
29128  while (i < ndraw)
29129  {
29130  // Picking the actual contacts
29131  int which = static_cast<int>(std::floor(n_infectious * m->runif()));
29132 
29133  /* There is a bug in which runif() returns 1.0. It is rare, but
29134  * we saw it here. See the Notes section in the C++ manual
29135  * https://en.cppreference.com/mwiki/index.php?title=cpp/numeric/random/uniform_real_distribution&oldid=133329
29136  * And the reported bug in GCC:
29137  * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176
29138  *
29139  */
29140  if (which == static_cast<int>(n_infectious))
29141  --which;
29142 
29143  epiworld::Agent<> & neighbor = *model->infectious[which];
29144 
29145  // Can't sample itself
29146  if (neighbor.get_id() == p->get_id())
29147  continue;
29148 
29149  // We successfully drew a contact, so we increment the counter
29150  i++;
29151 
29152  // No virus, the error!!
29153  if (neighbor.get_virus() == nullptr)
29154  throw std::logic_error("The neighbor has no virus.");
29155 
29156  // Only prodomal individuals can transmit
29157  if (neighbor.get_state() != model->PRODROMAL)
29158  throw std::logic_error(
29159  "The neighbor is not in the prodromal state. The state is: " +
29160  std::to_string(neighbor.get_state())
29161  );
29162 
29163  auto & v = neighbor.get_virus();
29164 
29165  #ifdef EPI_DEBUG
29166  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
29167  throw std::logic_error("Trying to add an extra element to a temporal array outside of the range.");
29168  #endif
29169 
29170  /* And it is a function of susceptibility_reduction as well */
29171  m->array_double_tmp[nviruses_tmp] =
29172  (1.0 - p->get_susceptibility_reduction(v, m)) *
29173  v->get_prob_infecting(m) *
29174  (1.0 - neighbor.get_transmission_reduction(v, m))
29175  ;
29176 
29177  m->array_virus_tmp[nviruses_tmp++] = &(*v);
29178 
29179  }
29180 
29181  // No virus to compute
29182  if (nviruses_tmp == 0u)
29183  return;
29184 
29185  // Running the roulette
29186  int which = roulette(nviruses_tmp, m);
29187 
29188  if (which < 0)
29189  return;
29190 
29191  p->set_virus(*m->array_virus_tmp[which], m);
29192 
29193  return;
29194 
29195 };
29196 
29197 LOCAL_UPDATE_FUN(m_update_exposed) {
29198 
29199  if (m->runif() < (1.0/p->get_virus()->get_incubation(m)))
29200  p->change_state(m, ModelMeaslesSchool<TSeq>::PRODROMAL);
29201 
29202  return;
29203 
29204 };
29205 
29206 LOCAL_UPDATE_FUN(m_update_prodromal) {
29207 
29208  if (m->runif() < (1.0/m->par("Prodromal period")))
29209  {
29210 
29211  GET_MODEL(m, model);
29212  model->day_rash_onset[p->get_id()] = m->today();
29213  p->change_state(m, ModelMeaslesSchool<TSeq>::RASH);
29214 
29215  }
29216 
29217  return;
29218 
29219 };
29220 
29221 LOCAL_UPDATE_FUN(m_update_rash) {
29222 
29223 
29224  GET_MODEL(m, model);
29225 
29226  #ifdef EPI_DEBUG
29227  if (static_cast<int>(model->day_flagged.size()) <= p->get_id())
29228  throw std::logic_error(
29229  "The agent is not in the list of quarantined or isolated agents: " +
29230  std::to_string(p->get_id()) +
29231  " vs " +
29232  std::to_string(model->day_flagged.size()) +
29233  ". The model has " + std::to_string(model->size()) + " agents."
29234  );
29235  #endif
29236 
29237  // Checking if the agent will be detected or not
29238  // How many days since detected
29239  bool detected = false;
29240  if (
29241  (m->par("Isolation period") >= 0) &&
29242  (m->runif() < 1.0/m->par("Days undetected"))
29243  )
29244  {
29245  model->system_quarantine_triggered = true;
29246  detected = true;
29247 
29248  }
29249 
29250  // Probability of Staying in the rash period vs becoming
29251  // hospitalized
29252  m->array_double_tmp[0] = 1.0/m->par("Rash period");
29253  m->array_double_tmp[1] = m->par("Hospitalization rate");
29254 
29255  // Sampling from the probabilities
29256  SAMPLE_FROM_PROBS(2, which);
29257 
29258  // Recovers
29259  if (which == 2)
29260  {
29261  p->rm_virus(
29262  m,
29263  detected ?
29264  ModelMeaslesSchool::ISOLATED_RECOVERED:
29265  ModelMeaslesSchool::RECOVERED
29266  );
29267  }
29268  else if (which == 1)
29269  {
29270  // If hospitalized, then the agent is removed from the system
29271  // effectively
29272  p->change_state(
29273  m,
29274  detected ?
29275  ModelMeaslesSchool::DETECTED_HOSPITALIZED :
29276  ModelMeaslesSchool::HOSPITALIZED
29277  );
29278  }
29279  else if (which != 0)
29280  {
29281  throw std::logic_error("The roulette returned an unexpected value.");
29282  }
29283  else if ((which == 0u) && detected)
29284  {
29285  // If the agent is not hospitalized, then it is moved to
29286  // isolation.
29287  p->change_state(m, ModelMeaslesSchool::ISOLATED);
29288  }
29289 
29290 };
29291 
29292 LOCAL_UPDATE_FUN(m_update_isolated) {
29293 
29294  GET_MODEL(m, model);
29295 
29296  // Figuring out if the agent can be released from isolation
29297  // if the quarantine period is over.
29298  int days_since = m->today() - model->day_rash_onset[p->get_id()];
29299 
29300  bool unisolate =
29301  (m->par("Isolation period") <= days_since) ?
29302  true: false;
29303 
29304  // Probability of staying in the rash period vs becoming
29305  // hospitalized
29306  m->array_double_tmp[0] = 1.0/m->par("Rash period");
29307  m->array_double_tmp[1] = m->par("Hospitalization rate");
29308 
29309  // Sampling from the probabilities
29310  SAMPLE_FROM_PROBS(2, which);
29311 
29312  // Recovers
29313  if (which == 2u)
29314  {
29315  if (unisolate)
29316  {
29317  p->rm_virus(
29318  m,
29319  ModelMeaslesSchool::RECOVERED
29320  );
29321  }
29322  else
29323  p->rm_virus(
29324  m, ModelMeaslesSchool::ISOLATED_RECOVERED
29325  );
29326  }
29327 
29328  // If hospitalized, then the agent is removed from the system
29329  else if (which == 1u)
29330  {
29331  p->change_state(
29332  m,
29333  // HOSPITALIZED
29334  unisolate ?
29335  ModelMeaslesSchool::HOSPITALIZED :
29336  ModelMeaslesSchool::DETECTED_HOSPITALIZED
29337  );
29338  }
29339  // If neither hospitalized nor recovered, then the agent is
29340  // still under isolation, unless the quarantine period is over.
29341  else if ((which == 0u) && unisolate)
29342  {
29343  p->change_state(m, ModelMeaslesSchool::RASH);
29344  }
29345 
29346 }
29347 
29348 LOCAL_UPDATE_FUN(m_update_isolated_recovered) {
29349 
29350  GET_MODEL(m, model);
29351 
29352  // Figuring out if the agent can be released from isolation
29353  // if the quarantine period is over.
29354  int days_since = m->today() - model->day_rash_onset[p->get_id()];
29355 
29356  bool unisolate =
29357  (m->par("Isolation period") <= days_since) ?
29358  true: false;
29359 
29360  if (unisolate)
29361  p->change_state(m, ModelMeaslesSchool::RECOVERED);
29362 
29363 }
29364 
29365 LOCAL_UPDATE_FUN(m_update_q_exposed) {
29366 
29367  // How many days since quarantine started
29368  GET_MODEL(m, model);
29369  int days_since =
29370  m->today() - model->day_flagged[p->get_id()];
29371 
29372  bool unquarantine =
29373  (m->par("Quarantine period") <= days_since) ?
29374  true: false;
29375 
29376  // Will develop prodromal symptoms?
29377  if (m->runif() < (1.0/p->get_virus()->get_incubation(m)))
29378  {
29379  // If the quarantine period is over, then they are moved to
29380  // the prodromal period. Otherwise, they are moved to the
29381  // quarantined prodromal period.
29382  if (unquarantine)
29383  p-> change_state(
29384  m,
29385  ModelMeaslesSchool::PRODROMAL
29386  );
29387  else
29388  p->change_state(
29389  m,
29390  ModelMeaslesSchool::QUARANTINED_PRODROMAL
29391  );
29392 
29393  }
29394  else if (unquarantine)
29395  {
29396  p->change_state(
29397  m,
29398  ModelMeaslesSchool::EXPOSED
29399  );
29400  }
29401 
29402 }
29403 
29404 LOCAL_UPDATE_FUN(m_update_q_susceptible) {
29405 
29406  GET_MODEL(m, model);
29407  int days_since =
29408  m->today() - model->day_flagged[p->get_id()];
29409 
29410  if (days_since >= m->par("Quarantine period"))
29411  p->change_state(m, ModelMeaslesSchool::SUSCEPTIBLE);
29412 
29413 }
29414 
29415 LOCAL_UPDATE_FUN(m_update_q_prodromal) {
29416 
29417  GET_MODEL(m, model);
29418 
29419  // Otherwise, these are moved to the prodromal period, if
29420  // the quanrantine period is over.
29421  int days_since = m->today() - model->day_flagged[p->get_id()];
29422 
29423  bool unquarantine =
29424  (m->par("Quarantine period") <= days_since) ?
29425  true: false;
29426 
29427  // Develops rash?
29428  if (m->runif() < (1.0/m->par("Prodromal period")))
29429  {
29430  model->day_rash_onset[p->get_id()] = m->today();
29431  p->change_state(m, ModelMeaslesSchool::ISOLATED);
29432  }
29433  else
29434  {
29435 
29436  if (unquarantine)
29437  p->change_state(m, ModelMeaslesSchool::PRODROMAL);
29438 
29439  }
29440 
29441 }
29442 
29443 LOCAL_UPDATE_FUN(m_update_q_recovered) {
29444 
29445  GET_MODEL(m, model);
29446  int days_since = m->today() - model->day_flagged[p->get_id()];
29447 
29448  if (days_since >= m->par("Quarantine period"))
29449  p->change_state(m, ModelMeaslesSchool::RECOVERED);
29450 
29451 }
29452 
29453 LOCAL_UPDATE_FUN(m_update_hospitalized) {
29454 
29455  // The agent is removed from the system
29456  if (m->runif() < 1.0/m->par("Hospitalization period"))
29457  p->rm_virus(m, ModelMeaslesSchool::RECOVERED);
29458 
29459  return;
29460 
29461 }
29462 
29463 
29464 template<typename TSeq>
29466  ModelMeaslesSchool<TSeq> & model,
29467  epiworld_fast_uint n,
29468  epiworld_fast_uint n_exposed,
29469  // Disease parameters
29470  epiworld_double contact_rate,
29471  epiworld_double transmission_rate,
29472  epiworld_double vax_efficacy,
29473  epiworld_double vax_reduction_recovery_rate,
29474  epiworld_double incubation_period,
29475  epiworld_double prodromal_period,
29476  epiworld_double rash_period,
29477  epiworld_double days_undetected,
29478  epiworld_double hospitalization_rate,
29479  epiworld_double hospitalization_period,
29480  // Policy parameters
29481  epiworld_double prop_vaccinated,
29482  epiworld_fast_int quarantine_period,
29483  epiworld_double quarantine_willingness,
29484  epiworld_fast_int isolation_period
29485 ) {
29486 
29487  model.add_state("Susceptible", this->m_update_susceptible);
29488  model.add_state("Exposed", this->m_update_exposed);
29489  model.add_state("Prodromal", this->m_update_prodromal);
29490  model.add_state("Rash", this->m_update_rash);
29491  model.add_state("Isolated", this->m_update_isolated);
29492  model.add_state(
29493  "Isolated Recovered", this->m_update_isolated_recovered
29494  );
29495  model.add_state("Detected Hospitalized", this->m_update_hospitalized);
29496  model.add_state(
29497  "Quarantined Exposed", this->m_update_q_exposed
29498  );
29499 
29500  model.add_state(
29501  "Quarantined Susceptible", this->m_update_q_susceptible
29502  );
29503 
29504  model.add_state(
29505  "Quarantined Prodromal", this->m_update_q_prodromal
29506  );
29507 
29508  model.add_state(
29509  "Quarantined Recovered", this->m_update_q_recovered
29510  );
29511 
29512  model.add_state("Hospitalized", this->m_update_hospitalized);
29513 
29514  model.add_state("Recovered");
29515 
29516  // Adding the model parameters
29517  model.add_param(contact_rate, "Contact rate");
29518  model.add_param(transmission_rate, "Transmission rate");
29519  model.add_param(incubation_period, "Incubation period");
29520  model.add_param(prodromal_period, "Prodromal period");
29521  model.add_param(rash_period, "Rash period");
29522  model.add_param(days_undetected, "Days undetected");
29523  model.add_param(quarantine_period, "Quarantine period");
29524  model.add_param(
29525  quarantine_willingness, "Quarantine willingness"
29526  );
29527  model.add_param(isolation_period, "Isolation period");
29528  model.add_param(hospitalization_rate, "Hospitalization rate");
29529  model.add_param(hospitalization_period, "Hospitalization period");
29530  model.add_param(prop_vaccinated, "Vaccination rate");
29531  model.add_param(vax_efficacy, "Vax efficacy");
29532  model.add_param(vax_reduction_recovery_rate, "(IGNORED) Vax improved recovery");
29533 
29534  // Designing the disease
29535  Virus<> measles("Measles");
29536  measles.set_state(EXPOSED, RECOVERED);
29537  measles.set_prob_infecting(&model("Transmission rate"));
29538  measles.set_prob_recovery(&model("Rash period"));
29539  measles.set_incubation(&model("Incubation period"));
29540  measles.set_distribution(
29541  distribute_virus_randomly(n_exposed, false)
29542  );
29543 
29544  model.add_virus(measles);
29545 
29546  // Designing the vaccine
29547  Tool<> vaccine("Vaccine");
29548  vaccine.set_susceptibility_reduction(&model("Vax efficacy"));
29549  vaccine.set_recovery_enhancer(&model("(IGNORED) Vax improved recovery"));
29550  vaccine.set_distribution(
29551  distribute_tool_randomly(prop_vaccinated, true)
29552  );
29553 
29554  model.add_tool(vaccine);
29555 
29556  // Global actions
29557  model.add_globalevent(this->m_update_model, "Update model");
29558  model.queuing_off();
29559 
29560  // Setting the population
29561  model.agents_empty_graph(n);
29562 
29563  return;
29564 
29565 }
29566 
29567 template<typename TSeq>
29569  epiworld_fast_uint n,
29570  epiworld_fast_uint n_exposed,
29571  // Disease parameters
29572  epiworld_double contact_rate,
29573  epiworld_double transmission_rate,
29574  epiworld_double vax_efficacy,
29575  epiworld_double vax_reduction_recovery_rate,
29576  epiworld_double incubation_period,
29577  epiworld_double prodromal_period,
29578  epiworld_double rash_period,
29579  epiworld_double days_undetected,
29580  epiworld_double hospitalization_rate,
29581  epiworld_double hospitalization_period,
29582  // Policy parameters
29583  epiworld_double prop_vaccinated,
29584  epiworld_fast_int quarantine_period,
29585  epiworld_double quarantine_willingness,
29586  epiworld_fast_int isolation_period
29587 
29588 ) {
29589 
29591  *this,
29592  n,
29593  n_exposed,
29594  contact_rate,
29595  transmission_rate,
29596  vax_efficacy,
29597  vax_reduction_recovery_rate,
29598  incubation_period,
29599  prodromal_period,
29600  rash_period,
29601  days_undetected,
29602  hospitalization_rate,
29603  hospitalization_period,
29604  prop_vaccinated,
29605  quarantine_period,
29606  quarantine_willingness,
29607  isolation_period
29608  );
29609 
29610  return;
29611 
29612 }
29613 
29614 #undef SAMPLE_FROM_PROBS
29615 #undef LOCAL_UPDATE_FUN
29616 #undef GET_MODEL
29617 #endif
29618 /*//////////////////////////////////////////////////////////////////////////////
29620 
29621  End of -include/epiworld/models/measlesschool.hpp-
29622 
29625 
29626 
29627 /*//////////////////////////////////////////////////////////////////////////////
29629 
29630  Start of -include/epiworld/models/seirmixingquarantine.hpp-
29631 
29634 
29635 
29636 #ifndef EPIWORLD_MODELS_SEIRMIXINGQUARANTINE_HPP
29637 #define EPIWORLD_MODELS_SEIRMIXINGQUARANTINE_HPP
29638 
29639 using namespace epiworld;
29640 
29641 #define MM(i, j, n) \
29642  j * n + i
29643 
29644 #if __cplusplus >= 202302L
29645  // C++23 or later
29646  #define GET_MODEL(model, output) \
29647  auto * output = dynamic_cast< ModelSEIRMixingQuarantine<TSeq> * >( (model) ); \
29648  /*Using the [[assume(...)]] to avoid the compiler warning \
29649  if the standard is C++23 or later */ \
29650  [[assume((output) != nullptr)]];
29651 #else
29652  // C++17 or C++20
29653  #define GET_MODEL(model, output) \
29654  auto * output = dynamic_cast< ModelSEIRMixingQuarantine<TSeq> * >( (model) ); \
29655  assert((output) != nullptr); // Use assert for runtime checks
29656 #endif
29657 
29658 #define SAMPLE_FROM_PROBS(n, ans) \
29659  size_t ans; \
29660  epiworld_double p_total = m->runif(); \
29661  for (ans = 0u; ans < n; ++ans) \
29662  { \
29663  if (p_total < m->array_double_tmp[ans]) \
29664  break; \
29665  m->array_double_tmp[ans + 1] += m->array_double_tmp[ans]; \
29666  }
29667 
29699 template<typename TSeq = EPI_DEFAULT_TSEQ>
29700 class ModelSEIRMixingQuarantine : public Model<TSeq>
29701 {
29702 private:
29703 
29704  // Vector of vectors of infected agents
29705  std::vector< size_t > infected;
29706 
29707  // Number of infected agents in each group
29708  std::vector< size_t > n_infected_per_group;
29709 
29710  // Where the agents start in the `infected` vector
29711  std::vector< size_t > entity_indices;
29712 
29713  void m_update_infected_list();
29714  std::vector< size_t > sampled_agents;
29715  size_t sample_agents(
29716  Agent<TSeq> * agent,
29717  std::vector< size_t > & sampled_agents
29718  );
29719  std::vector< double > adjusted_contact_rate;
29720  std::vector< double > contact_matrix;
29721 
29722  #ifdef EPI_DEBUG
29723  std::vector< int > sampled_sizes;
29724  #endif
29725 
29726  // Update functions
29727  static void m_update_susceptible(Agent<TSeq> * p, Model<TSeq> * m);
29728  static void m_update_exposed(Agent<TSeq> * p, Model<TSeq> * m);
29729  static void m_update_infected(Agent<TSeq> * p, Model<TSeq> * m);
29730  static void m_update_isolated(Agent<TSeq> * p, Model<TSeq> * m);
29731  static void m_update_quarantine_suscep(Agent<TSeq> * p, Model<TSeq> * m);
29732  static void m_update_quarantine_exposed(Agent<TSeq> * p, Model<TSeq> * m);
29733  static void m_update_hospitalized(Agent<TSeq> * p, Model<TSeq> * m);
29734  static void m_update_isolated_recovered(Agent<TSeq> * p, Model<TSeq> * m);
29735 
29736  // Data about the quarantine process
29737  std::vector< bool > quarantine_willingness;
29738  std::vector< bool > isolation_willingness;
29739  std::vector< size_t > agent_quarantine_triggered;
29740  std::vector< int > day_flagged;
29741  std::vector< int > day_onset;
29742  std::vector< int > day_exposed;
29743 
29744  void m_quarantine_process();
29745  static void m_update_model(Model<TSeq> * m);
29746 
29747  // We will limit tracking to up to EPI_MAX_TRACKING
29748  std::vector< size_t > tracking_matrix;
29749  std::vector< size_t > tracking_matrix_size;
29750 
29751  void m_add_tracking(size_t infected_id, size_t agent_id);
29752 
29753 public:
29754 
29755  static const int SUSCEPTIBLE = 0;
29756  static const int EXPOSED = 1;
29757  static const int INFECTED = 2;
29758  static const int ISOLATED = 3;
29759  static const int DETECTED_HOSPITALIZED = 4;
29760  static const int QUARANTINED_SUSCEPTIBLE = 5;
29761  static const int QUARANTINED_EXPOSED = 6;
29762  static const int ISOLATED_RECOVERED = 7;
29763  static const int HOSPITALIZED = 8;
29764  static const int RECOVERED = 9;
29765 
29766  static const size_t QUARANTINE_PROCESS_INACTIVE = 0u;
29767  static const size_t QUARANTINE_PROCESS_ACTIVE = 1u;
29768  static const size_t QUARANTINE_PROCESS_DONE = 2u;
29769 
29771 
29797  const std::string & vname,
29798  epiworld_fast_uint n,
29799  epiworld_double prevalence,
29800  epiworld_double contact_rate,
29801  epiworld_double transmission_rate,
29802  epiworld_double avg_incubation_days,
29803  epiworld_double recovery_rate,
29804  std::vector< double > contact_matrix,
29805  epiworld_double hospitalization_rate,
29806  epiworld_double hospitalization_period,
29807  // Policy parameters
29808  epiworld_double days_undetected,
29809  epiworld_fast_int quarantine_period,
29810  epiworld_double quarantine_willingness,
29811  epiworld_double isolation_willingness,
29812  epiworld_fast_int isolation_period,
29813  epiworld_double contact_tracing_success_rate = 1.0,
29814  epiworld_fast_uint contact_tracing_days_prior = 4u
29815  );
29816 
29839  const std::string & vname,
29840  epiworld_fast_uint n,
29841  epiworld_double prevalence,
29842  epiworld_double contact_rate,
29843  epiworld_double transmission_rate,
29844  epiworld_double avg_incubation_days,
29845  epiworld_double recovery_rate,
29846  std::vector< double > contact_matrix,
29847  epiworld_double hospitalization_rate,
29848  epiworld_double hospitalization_period,
29849  // Policy parameters
29850  epiworld_double days_undetected,
29851  epiworld_fast_int quarantine_period,
29852  epiworld_double quarantine_willingness,
29853  epiworld_double isolation_willingness,
29854  epiworld_fast_int isolation_period,
29855  epiworld_double contact_tracing_success_rate = 1.0,
29856  epiworld_fast_uint contact_tracing_days_prior = 4u
29857  );
29858 
29866  epiworld_fast_uint ndays,
29867  int seed = -1
29868  );
29869 
29873  void reset();
29874 
29879  Model<TSeq> * clone_ptr();
29880 
29889  std::vector< double > proportions_,
29890  std::vector< int > queue_ = {}
29891  );
29892 
29897  void set_contact_matrix(std::vector< double > cmat)
29898  {
29899  contact_matrix = cmat;
29900  return;
29901  };
29902 
29907  std::vector< double > get_contact_matrix() const
29908  {
29909  return contact_matrix;
29910  };
29911 
29916  std::vector< size_t > get_agent_quarantine_triggered() const
29917  {
29918  return agent_quarantine_triggered;
29919  };
29920 
29925  std::vector< bool > get_quarantine_willingness() const
29926  {
29927  return quarantine_willingness;
29928  };
29929 
29934  std::vector< bool > get_isolation_willingness() const
29935  {
29936  return isolation_willingness;
29937  };
29938 
29939 };
29940 
29941 template<typename TSeq>
29943 {
29944  GET_MODEL(m, model);
29945  model->m_quarantine_process();
29946  model->events_run();
29947  model->m_update_infected_list();
29948  return;
29949 }
29950 
29951 template<typename TSeq>
29953  size_t infected_id,
29954  size_t agent_id
29955 )
29956 {
29957 
29958  // We avoid the math if there's no point in tracking anymore
29959  if (agent_quarantine_triggered[infected_id] >= QUARANTINE_PROCESS_DONE)
29960  return;
29961 
29962  // We avoid the math if the contact happened before
29963  // the lower bound of the contact tracing
29964  size_t days_since_onset = Model<TSeq>::today() - day_onset[infected_id];
29965  if (days_since_onset >
29966  Model<TSeq>::par("Contact tracing days prior")
29967  )
29968  return;
29969 
29970 
29971  // If we are overflow, we start from the beginning
29972  size_t loc = tracking_matrix_size[infected_id] % EPI_MAX_TRACKING;
29973  tracking_matrix[MM(infected_id, loc, Model<TSeq>::size())] = agent_id;
29974 
29975  // We increase the size of the tracking matrix
29976  tracking_matrix_size[infected_id]++;
29977 
29978  return;
29979 }
29980 
29981 
29982 template<typename TSeq>
29984 {
29985 
29986  auto & agents = Model<TSeq>::get_agents();
29987 
29988  std::fill(n_infected_per_group.begin(), n_infected_per_group.end(), 0u);
29989 
29990  for (auto & a : agents)
29991  {
29992 
29993  if (a.get_state() == ModelSEIRMixingQuarantine<TSeq>::INFECTED)
29994  {
29995  if (a.get_n_entities() > 0u)
29996  {
29997  const auto & entity = a.get_entity(0u);
29998  infected[
29999  // Position of the group in the `infected` vector
30000  entity_indices[entity.get_id()] +
30001  // Position of the agent in the group
30002  n_infected_per_group[entity.get_id()]++
30003  ] = a.get_id();
30004 
30005  }
30006  }
30007 
30008  }
30009 
30010  return;
30011 
30012 }
30013 
30014 template<typename TSeq>
30016  epiworld::Agent<TSeq> * agent,
30017  std::vector< size_t > & sampled_agents
30018  )
30019 {
30020 
30021  size_t agent_group_id = agent->get_entity(0u).get_id();
30022  size_t ngroups = this->entities.size();
30023 
30024  int samp_id = 0;
30025  for (size_t g = 0; g < ngroups; ++g)
30026  {
30027 
30028  size_t group_size = n_infected_per_group[g];
30029 
30030  if (group_size == 0u)
30031  continue;
30032 
30033  // How many from this entity?
30034  int nsamples = epiworld::Model<TSeq>::rbinom(
30035  group_size,
30036  adjusted_contact_rate[g] * contact_matrix[
30037  MM(agent_group_id, g, ngroups)
30038  ]
30039  );
30040 
30041  if (nsamples == 0)
30042  continue;
30043 
30044  // Sampling from the entity
30045  for (int s = 0; s < nsamples; ++s)
30046  {
30047 
30048  // Randomly selecting an agent
30049  int which = epiworld::Model<TSeq>::runif() * group_size;
30050 
30051  // Correcting overflow error
30052  if (which >= static_cast<int>(group_size))
30053  which = static_cast<int>(group_size) - 1;
30054 
30055  #ifdef EPI_DEBUG
30056  auto & a = this->population.at(infected.at(entity_indices[g] + which));
30057  #else
30058  auto & a = this->get_agent(infected[entity_indices[g] + which]);
30059  #endif
30060 
30061  #ifdef EPI_DEBUG
30062  if (a.get_state() != ModelSEIRMixingQuarantine<TSeq>::INFECTED)
30063  throw std::logic_error(
30064  "The agent is not infected, but it should be."
30065  );
30066  #endif
30067 
30068  // Can't sample itself
30069  if (a.get_id() == agent->get_id())
30070  continue;
30071 
30072  sampled_agents[samp_id++] = a.get_id();
30073 
30074  }
30075 
30076  }
30077 
30078  return samp_id;
30079 
30080 }
30081 
30082 template<typename TSeq>
30084  epiworld_fast_uint ndays,
30085  int seed
30086 )
30087 {
30088 
30089  Model<TSeq>::run(ndays, seed);
30090 
30091  return *this;
30092 
30093 }
30094 
30095 template<typename TSeq>
30097 {
30098 
30100 
30101  // Checking contact matrix's rows add to one
30102  size_t nentities = this->entities.size();
30103  if (this->contact_matrix.size() != nentities*nentities)
30104  throw std::length_error(
30105  std::string("The contact matrix must be a square matrix of size ") +
30106  std::string("nentities x nentities. ") +
30107  std::to_string(this->contact_matrix.size()) +
30108  std::string(" != ") + std::to_string(nentities*nentities) +
30109  std::string(".")
30110  );
30111 
30112  for (size_t i = 0u; i < this->entities.size(); ++i)
30113  {
30114  double sum = 0.0;
30115  for (size_t j = 0u; j < this->entities.size(); ++j)
30116  {
30117  if (this->contact_matrix[MM(i, j, nentities)] < 0.0)
30118  throw std::range_error(
30119  std::string("The contact matrix must be non-negative. ") +
30120  std::to_string(this->contact_matrix[MM(i, j, nentities)]) +
30121  std::string(" < 0.")
30122  );
30123  sum += this->contact_matrix[MM(i, j, nentities)];
30124  }
30125  if (sum < 0.999 || sum > 1.001)
30126  throw std::range_error(
30127  std::string("The contact matrix must have rows that add to one. ") +
30128  std::to_string(sum) +
30129  std::string(" != 1.")
30130  );
30131  }
30132 
30133  // Do it the first time only
30134  sampled_agents.resize(Model<TSeq>::size());
30135 
30136  // We only do it once
30137  n_infected_per_group.resize(this->entities.size(), 0u);
30138  std::fill(n_infected_per_group.begin(), n_infected_per_group.end(), 0u);
30139 
30140  // We are assuming one agent per entity
30141  infected.resize(Model<TSeq>::size());
30142  std::fill(infected.begin(), infected.end(), 0u);
30143 
30144  // This will say when do the groups start in the `infected` vector
30145  entity_indices.resize(this->entities.size(), 0u);
30146  std::fill(entity_indices.begin(), entity_indices.end(), 0u);
30147  for (size_t i = 1u; i < this->entities.size(); ++i)
30148  {
30149 
30150  entity_indices[i] +=
30151  this->entities[i - 1].size() +
30152  entity_indices[i - 1]
30153  ;
30154 
30155  }
30156 
30157  // Adjusting contact rate
30158  adjusted_contact_rate.clear();
30159  adjusted_contact_rate.resize(this->entities.size(), 0.0);
30160 
30161  for (size_t i = 0u; i < this->entities.size(); ++i)
30162  {
30163 
30164  adjusted_contact_rate[i] =
30165  Model<TSeq>::get_param("Contact rate") /
30166  static_cast< epiworld_double > (this->get_entity(i).size());
30167 
30168 
30169  // Possibly correcting for a small number of agents
30170  if (adjusted_contact_rate[i] > 1.0)
30171  adjusted_contact_rate[i] = 1.0;
30172 
30173  }
30174 
30175  this->m_update_infected_list();
30176 
30177  // Setting up the quarantine parameters
30178  quarantine_willingness.resize(this->size(), false);
30179  isolation_willingness.resize(this->size(), false);
30180  for (size_t idx = 0; idx < quarantine_willingness.size(); ++idx)
30181  {
30182  quarantine_willingness[idx] =
30183  Model<TSeq>::runif() < this->par("Quarantine willingness");
30184  isolation_willingness[idx] =
30185  Model<TSeq>::runif() < this->par("Isolation willingness");
30186  }
30187 
30188  agent_quarantine_triggered.resize(this->size(), 0u);
30189  std::fill(
30190  agent_quarantine_triggered.begin(),
30191  agent_quarantine_triggered.end(),
30192  0u
30193  );
30194 
30195  day_flagged.resize(this->size(), 0);
30196  std::fill(
30197  day_flagged.begin(),
30198  day_flagged.end(),
30199  0
30200  );
30201 
30202  day_onset.resize(this->size(), 0);
30203  std::fill(
30204  day_onset.begin(),
30205  day_onset.end(),
30206  0
30207  );
30208 
30209  day_exposed.resize(this->size(), 0);
30210  std::fill(
30211  day_exposed.begin(),
30212  day_exposed.end(),
30213  0
30214  );
30215 
30216  // Tracking matrix
30217  tracking_matrix.resize(EPI_MAX_TRACKING * Model<TSeq>::size(), 0u);
30218  std::fill(tracking_matrix.begin(), tracking_matrix.end(), 0u);
30219 
30220  tracking_matrix_size.resize(Model<TSeq>::size(), 0u);
30221  std::fill(tracking_matrix_size.begin(), tracking_matrix_size.end(), 0u);
30222 
30223  return;
30224 
30225 }
30226 
30227 template<typename TSeq>
30229 {
30230 
30232  *dynamic_cast<const ModelSEIRMixingQuarantine<TSeq>*>(this)
30233  );
30234 
30235  #if __cplusplus >= 202302L
30236  // C++23 or later
30237  [[assume(ptr != nullptr)]];
30238  #else
30239  // C++17 or C++20
30240  assert(ptr != nullptr); // Use assert for runtime checks
30241  #endif
30242 
30243  return dynamic_cast< Model<TSeq> *>(ptr);
30244 
30245 }
30246 
30247 template<typename TSeq>
30249  Agent<TSeq> * p, Model<TSeq> * m
30250 ) {
30251 
30252  if (p->get_n_entities() == 0)
30253  return;
30254 
30255  // Downcasting to retrieve the sampler attached to the
30256  // class
30257  GET_MODEL(m, m_down);
30258 
30259  size_t ndraws = m_down->sample_agents(p, m_down->sampled_agents);
30260 
30261  #ifdef EPI_DEBUG
30262  m_down->sampled_sizes.push_back(static_cast<int>(ndraws));
30263  #endif
30264 
30265  if (ndraws == 0u)
30266  return;
30267 
30268  // Drawing from the set
30269  int nviruses_tmp = 0;
30270  for (size_t n = 0u; n < ndraws; ++n)
30271  {
30272 
30273  auto & neighbor = m->get_agent(m_down->sampled_agents[n]);
30274 
30275  auto & v = neighbor.get_virus();
30276 
30277  #ifdef EPI_DEBUG
30278  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
30279  throw std::logic_error(
30280  "Trying to add an extra element to a temporal array outside of the range."
30281  );
30282  #endif
30283 
30284  // Adding the current agent to the tracked interactions
30285  m_down->m_add_tracking(neighbor.get_id(), p->get_id());
30286 
30287  /* And it is a function of susceptibility_reduction as well */
30288  m->array_double_tmp[nviruses_tmp] =
30289  (1.0 - p->get_susceptibility_reduction(v, m)) *
30290  v->get_prob_infecting(m) *
30291  (1.0 - neighbor.get_transmission_reduction(v, m))
30292  ;
30293 
30294  m->array_virus_tmp[nviruses_tmp++] = &(*v);
30295 
30296  }
30297 
30298  // Running the roulette
30299  int which = roulette(nviruses_tmp, m);
30300 
30301  if (which < 0)
30302  return;
30303 
30304  p->set_virus(
30305  *m->array_virus_tmp[which],
30306  m,
30308  );
30309 
30310  return;
30311 
30312 };
30313 
30314 template<typename TSeq>
30316  Agent<TSeq> * p, Model<TSeq> * m
30317 ) {
30318 
30319  // Getting the virus
30320  auto & v = p->get_virus();
30321 
30322  // Does the agent become infected?
30323  if (m->runif() < 1.0/(v->get_incubation(m)))
30324  {
30325 
30326  p->change_state(m, ModelSEIRMixingQuarantine<TSeq>::INFECTED);
30327 
30328  GET_MODEL(m, model);
30329  model->day_onset[p->get_id()] = m->today();
30330 
30331  return;
30332 
30333  }
30334 
30335  return;
30336 
30337 };
30338 
30339 template<typename TSeq>
30341  Agent<TSeq> * p, Model<TSeq> * m
30342 ) {
30343 
30344  GET_MODEL(m, model);
30345 
30346  // Sampling whether the agent is detected or not
30347  bool detected = m->runif() < 1.0/m->par("Days undetected");
30348 
30349  // If detected and the entity can quarantine, we start
30350  // the quarantine process
30351  if (detected)
30352  {
30353  model->agent_quarantine_triggered[p->get_id()] =
30355  }
30356 
30357  // Checking if the agent is willing to isolate individually
30358  // This is separate from quarantine and can happen even if agent cannot quarantine
30359  bool isolation_detected = (m->par("Isolation period") >= 0) &&
30360  detected &&
30361  (model->isolation_willingness[p->get_id()])
30362  ;
30363 
30364  // Recording the date of detection
30365  if (isolation_detected)
30366  model->day_flagged[p->get_id()] = m->today();
30367 
30368  // Computing probabilities for state change
30369  const auto & v = p->get_virus();
30370  m->array_double_tmp[0] = 1.0 - (1.0 - v->get_prob_recovery(m)) *
30371  (1.0 - p->get_recovery_enhancer(v, m));
30372  m->array_double_tmp[1] = m->par("Hospitalization rate");
30373 
30374  SAMPLE_FROM_PROBS(2, which);
30375 
30376  if (which == 0) // Recovers
30377  {
30378  if (isolation_detected)
30379  {
30380  p->change_state(
30382  );
30383  }
30384  else
30385  {
30386  p->rm_virus(
30388  );
30389  }
30390 
30391  return;
30392  }
30393  else if (which == 1) // Hospitalized
30394  {
30395 
30396  if (detected)
30397  {
30398  p->change_state(
30400  );
30401  }
30402  else
30403  {
30404  p->change_state(
30406  );
30407  }
30408 
30409  }
30410  else if ((which == 2) && isolation_detected) // Nothing, but detected
30411  {
30412  // If the agent is detected, it goes to isolation
30413  p->change_state(
30415  );
30416 
30417  }
30418 
30419  return ;
30420 
30421 };
30422 
30423 template<typename TSeq>
30425  Agent<TSeq> * p, Model<TSeq> * m
30426 ) {
30427 
30428  GET_MODEL(m, model);
30429 
30430  // Figuring out if the agent can be released from isolation
30431  // if the quarantine period is over.
30432  int days_since = m->today() - model->day_onset[p->get_id()];
30433 
30434  bool unisolate =
30435  (m->par("Isolation period") <= days_since) ?
30436  true: false;
30437 
30438  // Sampling from the probabilities of recovery
30439  m->array_double_tmp[0] = 1.0 -
30440  (1.0 - p->get_virus()->get_prob_recovery(m)) *
30441  (1.0 - p->get_recovery_enhancer(p->get_virus(), m));
30442 
30443  // And hospitalization
30444  m->array_double_tmp[1] = m->par("Hospitalization rate");
30445 
30446  SAMPLE_FROM_PROBS(2, which);
30447 
30448  // Recovers
30449  if (which == 0)
30450  {
30451  if (unisolate)
30452  {
30453  p->rm_virus(
30454  m,
30456  );
30457  }
30458  else
30459  p->rm_virus(
30461  );
30462  }
30463  else if (which == 1)
30464  {
30465 
30466  if (unisolate)
30467  {
30468  p->change_state(
30470  );
30471  }
30472  else
30473  {
30474  p->change_state(
30476  );
30477  }
30478  }
30479  else if ((which == 2) && unisolate)
30480  {
30481  p->change_state(
30483  );
30484  }
30485 
30486 
30487 };
30488 
30489 template<typename TSeq>
30491  Agent<TSeq> * p, Model<TSeq> * m
30492 ) {
30493 
30494  GET_MODEL(m, model);
30495 
30496  // Figuring out if the agent can be released from quarantine
30497  // if the quarantine period is over.
30498  int days_since = m->today() - model->day_flagged[p->get_id()];
30499 
30500  bool unquarantine =
30501  (m->par("Quarantine period") <= days_since) ?
30502  true: false;
30503 
30504  if (unquarantine)
30505  {
30506  p->change_state(
30508  );
30509  }
30510 
30511 };
30512 
30513 template<typename TSeq>
30515  Agent<TSeq> * p, Model<TSeq> * m
30516 ) {
30517 
30518  GET_MODEL(m, model);
30519 
30520  // Figuring out if the agent can be released from quarantine
30521  // if the quarantine period is over.
30522  int days_since = m->today() - model->day_flagged[p->get_id()];
30523 
30524  bool unquarantine =
30525  (m->par("Quarantine period") <= days_since) ?
30526  true: false;
30527 
30528  if (m->runif() < 1.0/(p->get_virus()->get_incubation(m)))
30529  {
30530 
30531  // Recording the day of onset
30532  model->day_onset[p->get_id()] = m->today();
30533 
30534  // If the agent is unquarantined, it becomes infected
30535  if (unquarantine)
30536  {
30537  p->change_state(
30539  );
30540  }
30541  else
30542  {
30543  p->change_state(
30545  );
30546  }
30547 
30548  }
30549  else if (unquarantine)
30550  {
30551  p->change_state(
30553  );
30554  }
30555 
30556 };
30557 
30558 template<typename TSeq>
30560  Agent<TSeq> * p, Model<TSeq> * m
30561 ) {
30562 
30563  GET_MODEL(m, model);
30564 
30565  // Figuring out if the agent can be released from isolation
30566  // if the quarantine period is over.
30567  int days_since = m->today() - model->day_onset[p->get_id()];
30568 
30569  bool unisolate =
30570  (m->par("Isolation period") <= days_since) ?
30571  true: false;
30572 
30573  if (unisolate)
30574  {
30575  p->change_state(
30577  );
30578  }
30579 
30580 };
30581 
30582 template<typename TSeq>
30584  Agent<TSeq> * p, Model<TSeq> * m
30585 ) {
30586 
30587  // The agent is removed from the system
30588  if (m->runif() < 1.0/m->par("Hospitalization period"))
30590 
30591 };
30592 
30593 template<typename TSeq>
30595 
30596  // Process entity-level quarantine
30597  for (size_t agent_i = 0u; agent_i < Model<TSeq>::size(); ++agent_i)
30598  {
30599 
30600  // Checking if the quarantine in the agent was triggered
30601  // or not
30602  if (
30603  agent_quarantine_triggered[agent_i] !=
30605  )
30606  continue;
30607 
30608  if (this->par("Quarantine period") < 0)
30609  continue;
30610 
30611  // Getting the number of contacts, if it is greater
30612  // than the maximum, it means that we overflowed, so
30613  // we will only quarantine the first EPI_MAX_TRACKING
30614  size_t n_contacts = this->tracking_matrix_size[agent_i];
30615  if (n_contacts >= EPI_MAX_TRACKING)
30616  n_contacts = EPI_MAX_TRACKING;
30617 
30618  auto success_rate = this->par("Contact tracing success rate");
30619  for (size_t contact_i = 0u; contact_i < n_contacts; ++contact_i)
30620  {
30621 
30622  // Checking if we will detect the contact
30623  if (Model<TSeq>::runif() > success_rate)
30624  continue;
30625 
30626  size_t contact_id = this->tracking_matrix[
30627  MM(agent_i, contact_i, Model<TSeq>::size())
30628  ];
30629 
30630  auto & agent = Model<TSeq>::get_agent(contact_id);
30631 
30632  if (agent.get_state() > INFECTED)
30633  continue;
30634 
30635  // Agents with some tool won't be quarantined
30636  if (agent.get_n_tools() != 0u)
30637  continue;
30638 
30639  if (quarantine_willingness[contact_id])
30640  {
30641 
30642  switch (agent.get_state())
30643  {
30644  case SUSCEPTIBLE:
30645  agent.change_state(this, QUARANTINED_SUSCEPTIBLE);
30646  day_flagged[contact_id] = Model<TSeq>::today();
30647  break;
30648  case EXPOSED:
30649  agent.change_state(this, QUARANTINED_EXPOSED);
30650  day_flagged[contact_id] = Model<TSeq>::today();
30651  break;
30652  case INFECTED:
30653  if (isolation_willingness[contact_id])
30654  {
30655  agent.change_state(this, ISOLATED);
30656  day_flagged[contact_id] = Model<TSeq>::today();
30657  }
30658  break;
30659  default:
30660  throw std::logic_error(
30661  "The agent is not in a state that can be quarantined."
30662  );
30663  }
30664 
30665  }
30666  }
30667 
30668  // Setting the quarantine process off
30669  agent_quarantine_triggered[agent_i] = QUARANTINE_PROCESS_DONE;
30670  }
30671 
30672  return;
30673 }
30674 
30697 template<typename TSeq>
30700  const std::string & vname,
30701  epiworld_fast_uint n,
30702  epiworld_double prevalence,
30703  epiworld_double contact_rate,
30704  epiworld_double transmission_rate,
30705  epiworld_double avg_incubation_days,
30706  epiworld_double recovery_rate,
30707  std::vector< double > contact_matrix,
30708  epiworld_double hospitalization_rate,
30709  epiworld_double hospitalization_period,
30710  // Policy parameters
30711  epiworld_double days_undetected,
30712  epiworld_fast_int quarantine_period,
30713  epiworld_double quarantine_willingness,
30714  epiworld_double isolation_willingness,
30715  epiworld_fast_int isolation_period,
30716  epiworld_double contact_tracing_success_rate,
30717  epiworld_fast_uint contact_tracing_days_prior
30718  )
30719 {
30720 
30721  // Setting up the contact matrix
30722  this->contact_matrix = contact_matrix;
30723 
30724  // Setting up parameters
30725  model.add_param(contact_rate, "Contact rate");
30726  model.add_param(transmission_rate, "Prob. Transmission");
30727  model.add_param(recovery_rate, "Prob. Recovery");
30728  model.add_param(avg_incubation_days, "Avg. Incubation days");
30729  model.add_param(hospitalization_rate, "Hospitalization rate");
30730  model.add_param(hospitalization_period, "Hospitalization period");
30731  model.add_param(days_undetected, "Days undetected");
30732  model.add_param(quarantine_period, "Quarantine period");
30733  model.add_param(
30734  quarantine_willingness, "Quarantine willingness"
30735  );
30736  model.add_param(
30737  isolation_willingness, "Isolation willingness"
30738  );
30739  model.add_param(isolation_period, "Isolation period");
30740  model.add_param(
30741  contact_tracing_success_rate, "Contact tracing success rate"
30742  );
30743  model.add_param(
30744  contact_tracing_days_prior, "Contact tracing days prior"
30745  );
30746 
30747  // state
30748  model.add_state("Susceptible", m_update_susceptible);
30749  model.add_state("Exposed", m_update_exposed);
30750  model.add_state("Infected", m_update_infected);
30751  model.add_state("Isolated", m_update_isolated);
30752  model.add_state("Detected Hospitalized", m_update_hospitalized);
30753  model.add_state("Quarantined Susceptible", m_update_quarantine_suscep);
30754  model.add_state("Quarantined Exposed", m_update_quarantine_exposed);
30755  model.add_state("Isolated Recovered", m_update_isolated_recovered);
30756  model.add_state("Hospitalized", m_update_hospitalized);
30757  model.add_state("Recovered");
30758 
30759  // Global function
30760  model.add_globalevent(this->m_update_model, "Update infected individuals");
30761  model.queuing_off();
30762 
30763  // Preparing the virus -------------------------------------------
30764  epiworld::Virus<TSeq> virus(vname, prevalence, true);
30765  virus.set_state(
30769  );
30770 
30771  virus.set_prob_infecting(&model("Prob. Transmission"));
30772  virus.set_prob_recovery(&model("Prob. Recovery"));
30773  virus.set_incubation(&model("Avg. Incubation days"));
30774 
30775  model.add_virus(virus);
30776 
30777  model.queuing_off(); // No queuing need
30778 
30779  // Adding the empty population
30780  model.agents_empty_graph(n);
30781 
30782  model.set_name("SEIR with Mixing and Quarantine");
30783 
30784  return;
30785 
30786 }
30787 
30788 template<typename TSeq>
30790  const std::string & vname,
30791  epiworld_fast_uint n,
30792  epiworld_double prevalence,
30793  epiworld_double contact_rate,
30794  epiworld_double transmission_rate,
30795  epiworld_double avg_incubation_days,
30796  epiworld_double recovery_rate,
30797  std::vector< double > contact_matrix,
30798  epiworld_double hospitalization_rate,
30799  epiworld_double hospitalization_period,
30800  // Policy parameters
30801  epiworld_double days_undetected,
30802  epiworld_fast_int quarantine_period,
30803  epiworld_double quarantine_willingness,
30804  epiworld_double isolation_willingness,
30805  epiworld_fast_int isolation_period,
30806  epiworld_double contact_tracing_success_rate,
30807  epiworld_fast_uint contact_tracing_days_prior
30808  )
30809 {
30810 
30811  this->contact_matrix = contact_matrix;
30812 
30814  *this,
30815  vname,
30816  n,
30817  prevalence,
30818  contact_rate,
30819  transmission_rate,
30820  avg_incubation_days,
30821  recovery_rate,
30822  contact_matrix,
30823  hospitalization_rate,
30824  hospitalization_period,
30825  // Policy parameters
30826  days_undetected,
30827  quarantine_period,
30828  quarantine_willingness,
30829  isolation_willingness,
30830  isolation_period,
30831  contact_tracing_success_rate,
30832  contact_tracing_days_prior
30833  );
30834 
30835  return;
30836 
30837 }
30838 
30839 template<typename TSeq>
30841  std::vector< double > proportions_,
30842  std::vector< int > /* queue_ */
30843 )
30844 {
30845 
30847  create_init_function_seir<TSeq>(proportions_)
30848  ;
30849 
30850  return *this;
30851 
30852 }
30853 #undef MM
30854 #undef GET_MODEL
30855 #undef SAMPLE_FROM_PROBS
30856 #endif
30857 /*//////////////////////////////////////////////////////////////////////////////
30859 
30860  End of -include/epiworld/models/seirmixingquarantine.hpp-
30861 
30864 
30865 
30866 /*//////////////////////////////////////////////////////////////////////////////
30868 
30869  Start of -include/epiworld/models/measlesmixing.hpp-
30870 
30873 
30874 
30875 #ifndef EPIWORLD_MODELS_MEASLESMIXING_HPP
30876 #define EPIWORLD_MODELS_MEASLESMIXING_HPP
30877 
30878 using namespace epiworld;
30879 
30880 #define MM(i, j, n) \
30881  j * n + i
30882 
30883 #if __cplusplus >= 202302L
30884  // C++23 or later
30885  #define GET_MODEL(model, output) \
30886  auto * output = dynamic_cast< ModelMeaslesMixing<TSeq> * >( (model) ); \
30887  /*Using the [[assume(...)]] to avoid the compiler warning \
30888  if the standard is C++23 or later */ \
30889  [[assume((output) != nullptr)]];
30890 #else
30891  // C++17 or C++20
30892  #define GET_MODEL(model, output) \
30893  auto * output = dynamic_cast< ModelMeaslesMixing<TSeq> * >( (model) ); \
30894  assert((output) != nullptr); // Use assert for runtime checks
30895 #endif
30896 
30897 #define SAMPLE_FROM_PROBS(n, ans) \
30898  size_t ans; \
30899  epiworld_double p_total = m->runif(); \
30900  for (ans = 0u; ans < n; ++ans) \
30901  { \
30902  if (p_total < m->array_double_tmp[ans]) \
30903  break; \
30904  m->array_double_tmp[ans + 1] += m->array_double_tmp[ans]; \
30905  }
30906 
30944 template<typename TSeq = EPI_DEFAULT_TSEQ>
30945 class ModelMeaslesMixing : public Model<TSeq>
30946 {
30947 private:
30948 
30949  // Vector of vectors of infected agents (prodromal agents are infectious)
30950  std::vector< size_t > infectious;
30951 
30952  // Number of infectious agents in each group
30953  std::vector< size_t > n_infectious_per_group;
30954 
30955  // Where the agents start in the `infectious` vector
30956  std::vector< size_t > entity_indices;
30957 
30958  void m_update_infectious_list();
30959  std::vector< size_t > sampled_agents;
30960  size_t sample_agents(
30961  Agent<TSeq> * agent,
30962  std::vector< size_t > & sampled_agents
30963  );
30964  std::vector< double > adjusted_contact_rate;
30965  std::vector< double > contact_matrix;
30966 
30967  #ifdef EPI_DEBUG
30968  std::vector< int > sampled_sizes;
30969  #endif
30970 
30971  // Update functions
30972  static void m_update_susceptible(Agent<TSeq> * p, Model<TSeq> * m);
30973  static void m_update_exposed(Agent<TSeq> * p, Model<TSeq> * m);
30974  static void m_update_prodromal(Agent<TSeq> * p, Model<TSeq> * m);
30975  static void m_update_rash(Agent<TSeq> * p, Model<TSeq> * m);
30976  static void m_update_isolated(Agent<TSeq> * p, Model<TSeq> * m);
30977  static void m_update_isolated_recovered(Agent<TSeq> * p, Model<TSeq> * m);
30978  static void m_update_quarantine_suscep(Agent<TSeq> * p, Model<TSeq> * m);
30979  static void m_update_quarantine_exposed(Agent<TSeq> * p, Model<TSeq> * m);
30980  static void m_update_quarantine_prodromal(Agent<TSeq> * p, Model<TSeq> * m);
30981  static void m_update_quarantine_recovered(Agent<TSeq> * p, Model<TSeq> * m);
30982  static void m_update_hospitalized(Agent<TSeq> * p, Model<TSeq> * m);
30983 
30984  // Data about the quarantine process
30985  std::vector< bool > quarantine_willingness;
30986  std::vector< bool > isolation_willingness;
30987  std::vector< size_t > agent_quarantine_triggered;
30988  std::vector< int > day_flagged;
30989  std::vector< int > day_rash_onset;
30990  std::vector< int > day_exposed;
30991 
30992  void m_quarantine_process();
30993  static void m_update_model(Model<TSeq> * m);
30994 
30995  // We will limit tracking to up to EPI_MAX_TRACKING
30996  std::vector< size_t > tracking_matrix;
30997  std::vector< size_t > tracking_matrix_size;
30998  std::vector< size_t > tracking_matrix_date;
30999 
31000  void m_add_tracking(size_t infectious_id, size_t agent_id);
31001 
31002 public:
31003 
31004  static const int SUSCEPTIBLE = 0;
31005  static const int EXPOSED = 1;
31006  static const int PRODROMAL = 2;
31007  static const int RASH = 3;
31008  static const int ISOLATED = 4;
31009  static const int ISOLATED_RECOVERED = 5;
31010  static const int DETECTED_HOSPITALIZED = 6;
31011  static const int QUARANTINED_EXPOSED = 7;
31012  static const int QUARANTINED_SUSCEPTIBLE = 8;
31013  static const int QUARANTINED_PRODROMAL = 9;
31014  static const int QUARANTINED_RECOVERED = 10;
31015  static const int HOSPITALIZED = 11;
31016  static const int RECOVERED = 12;
31017 
31018  static const size_t QUARANTINE_PROCESS_INACTIVE = 0u;
31019  static const size_t QUARANTINE_PROCESS_ACTIVE = 1u;
31020  static const size_t QUARANTINE_PROCESS_DONE = 2u;
31021 
31022  ModelMeaslesMixing() {};
31023 
31051  ModelMeaslesMixing<TSeq> & model,
31052  epiworld_fast_uint n,
31053  epiworld_double prevalence,
31054  epiworld_double contact_rate,
31055  epiworld_double transmission_rate,
31056  epiworld_double vax_efficacy,
31057  epiworld_double vax_reduction_recovery_rate,
31058  epiworld_double incubation_period,
31059  epiworld_double prodromal_period,
31060  epiworld_double rash_period,
31061  std::vector< double > contact_matrix,
31062  epiworld_double hospitalization_rate,
31063  epiworld_double hospitalization_period,
31064  // Policy parameters
31065  epiworld_double days_undetected,
31066  epiworld_fast_int quarantine_period,
31067  epiworld_double quarantine_willingness,
31068  epiworld_double isolation_willingness,
31069  epiworld_fast_int isolation_period,
31070  epiworld_double prop_vaccinated,
31071  epiworld_double contact_tracing_success_rate = 1.0,
31072  epiworld_fast_uint contact_tracing_days_prior = 4u
31073  );
31074 
31100  epiworld_fast_uint n,
31101  epiworld_double prevalence,
31102  epiworld_double contact_rate,
31103  epiworld_double transmission_rate,
31104  epiworld_double vax_efficacy,
31105  epiworld_double vax_reduction_recovery_rate,
31106  epiworld_double incubation_period,
31107  epiworld_double prodromal_period,
31108  epiworld_double rash_period,
31109  std::vector< double > contact_matrix,
31110  epiworld_double hospitalization_rate,
31111  epiworld_double hospitalization_period,
31112  // Policy parameters
31113  epiworld_double days_undetected,
31114  epiworld_fast_int quarantine_period,
31115  epiworld_double quarantine_willingness,
31116  epiworld_double isolation_willingness,
31117  epiworld_fast_int isolation_period,
31118  epiworld_double prop_vaccinated,
31119  epiworld_double contact_tracing_success_rate = 1.0,
31120  epiworld_fast_uint contact_tracing_days_prior = 4u
31121  );
31122 
31130  epiworld_fast_uint ndays,
31131  int seed = -1
31132  );
31133 
31137  void reset();
31138 
31143  Model<TSeq> * clone_ptr();
31144 
31153  std::vector< double > proportions_,
31154  std::vector< int > queue_ = {}
31155  );
31156 
31161  void set_contact_matrix(std::vector< double > cmat)
31162  {
31163  contact_matrix = cmat;
31164  return;
31165  };
31166 
31171  std::vector< double > get_contact_matrix() const
31172  {
31173  return contact_matrix;
31174  };
31175 
31180  std::vector< size_t > get_agent_quarantine_triggered() const
31181  {
31182  return agent_quarantine_triggered;
31183  };
31184 
31189  std::vector< bool > get_quarantine_willingness() const
31190  {
31191  return quarantine_willingness;
31192  };
31193 
31198  std::vector< bool > get_isolation_willingness() const
31199  {
31200  return isolation_willingness;
31201  };
31202 
31203 };
31204 
31205 template<typename TSeq>
31207 {
31208  GET_MODEL(m, model);
31209  model->m_quarantine_process();
31210  model->events_run();
31211  model->m_update_infectious_list();
31212  return;
31213 }
31214 
31215 template<typename TSeq>
31217  size_t infectious_id,
31218  size_t agent_id
31219 )
31220 {
31221 
31222  // We avoid the math if there's no point in tracking anymore
31223  if (
31224  agent_quarantine_triggered[infectious_id] >=
31226  )
31227  return;
31228 
31229  // If we are overflow, we start from the beginning
31230  size_t loc = tracking_matrix_size[infectious_id] % EPI_MAX_TRACKING;
31231  loc = MM(infectious_id, loc, Model<TSeq>::size());
31232  tracking_matrix[loc] = agent_id;
31233  tracking_matrix_date[loc] = Model<TSeq>::today();
31234 
31235  // We increase the size of the tracking matrix
31236  tracking_matrix_size[infectious_id]++;
31237 
31238  return;
31239 }
31240 
31241 
31242 template<typename TSeq>
31244 {
31245 
31246  auto & agents = Model<TSeq>::get_agents();
31247 
31248  std::fill(n_infectious_per_group.begin(), n_infectious_per_group.end(), 0u);
31249 
31250  for (const auto & a : agents)
31251  {
31252 
31253  if (a.get_state() == ModelMeaslesMixing<TSeq>::PRODROMAL)
31254  {
31255  if (a.get_n_entities() > 0u)
31256  {
31257  const auto & entity = a.get_entity(0u);
31258  infectious[
31259  // Position of the group in the `infectious` vector
31260  entity_indices[entity.get_id()] +
31261  // Position of the agent in the group
31262  n_infectious_per_group[entity.get_id()]++
31263  ] = a.get_id();
31264 
31265  }
31266  }
31267 
31268  }
31269 
31270  return;
31271 
31272 }
31273 
31274 template<typename TSeq>
31276  epiworld::Agent<TSeq> * agent,
31277  std::vector< size_t > & sampled_agents
31278  )
31279 {
31280 
31281  size_t agent_group_id = agent->get_entity(0u).get_id();
31282  size_t ngroups = this->entities.size();
31283 
31284  int samp_id = 0;
31285  for (size_t g = 0; g < ngroups; ++g)
31286  {
31287 
31288  size_t group_size = n_infectious_per_group[g];
31289 
31290  if (group_size == 0u)
31291  continue;
31292 
31293  // How many from this entity?
31294  int nsamples = epiworld::Model<TSeq>::rbinom(
31295  group_size,
31296  adjusted_contact_rate[g] * contact_matrix[
31297  MM(agent_group_id, g, ngroups)
31298  ]
31299  );
31300 
31301  if (nsamples == 0)
31302  continue;
31303 
31304  // Sampling from the entity
31305  for (int s = 0; s < nsamples; ++s)
31306  {
31307 
31308  // Randomly selecting an agent
31309  int which = epiworld::Model<TSeq>::runif() * group_size;
31310 
31311  // Correcting overflow error
31312  if (which >= static_cast<int>(group_size))
31313  which = static_cast<int>(group_size) - 1;
31314 
31315  #ifdef EPI_DEBUG
31316  auto & a = this->population.at(infectious.at(entity_indices[g] + which));
31317  #else
31318  auto & a = this->get_agent(infectious[entity_indices[g] + which]);
31319  #endif
31320 
31321  #ifdef EPI_DEBUG
31322  if (a.get_state() != ModelMeaslesMixing<TSeq>::PRODROMAL)
31323  throw std::logic_error(
31324  "The agent is not in prodromal state, but it should be."
31325  );
31326  #endif
31327 
31328  // Can't sample itself
31329  if (a.get_id() == agent->get_id())
31330  continue;
31331 
31332  sampled_agents[samp_id++] = a.get_id();
31333 
31334  }
31335 
31336  }
31337 
31338  return samp_id;
31339 
31340 }
31341 
31342 template<typename TSeq>
31344  epiworld_fast_uint ndays,
31345  int seed
31346 )
31347 {
31348 
31349  Model<TSeq>::run(ndays, seed);
31350 
31351  return *this;
31352 
31353 }
31354 
31355 template<typename TSeq>
31357 {
31358 
31360 
31361  // Checking contact matrix's rows add to one
31362  size_t nentities = this->entities.size();
31363  if (this->contact_matrix.size() != nentities*nentities)
31364  throw std::length_error(
31365  std::string("The contact matrix must be a square matrix of size ") +
31366  std::string("nentities x nentities. ") +
31367  std::to_string(this->contact_matrix.size()) +
31368  std::string(" != ") + std::to_string(nentities*nentities) +
31369  std::string(".")
31370  );
31371 
31372  for (size_t i = 0u; i < this->entities.size(); ++i)
31373  {
31374  double sum = 0.0;
31375  for (size_t j = 0u; j < this->entities.size(); ++j)
31376  {
31377  if (this->contact_matrix[MM(i, j, nentities)] < 0.0)
31378  throw std::range_error(
31379  std::string("The contact matrix must be non-negative. ") +
31380  std::to_string(this->contact_matrix[MM(i, j, nentities)]) +
31381  std::string(" < 0.")
31382  );
31383  sum += this->contact_matrix[MM(i, j, nentities)];
31384  }
31385  if (sum < 0.999 || sum > 1.001)
31386  throw std::range_error(
31387  std::string("The contact matrix must have rows that add to one. ") +
31388  std::to_string(sum) +
31389  std::string(" != 1.")
31390  );
31391  }
31392 
31393  // Do it the first time only
31394  sampled_agents.resize(Model<TSeq>::size());
31395 
31396  // We only do it once
31397  n_infectious_per_group.resize(this->entities.size(), 0u);
31398  std::fill(n_infectious_per_group.begin(), n_infectious_per_group.end(), 0u);
31399 
31400  // We are assuming one agent per entity
31401  infectious.resize(Model<TSeq>::size());
31402  std::fill(infectious.begin(), infectious.end(), 0u);
31403 
31404  // This will say when do the groups start in the `infectious` vector
31405  entity_indices.resize(this->entities.size(), 0u);
31406  std::fill(entity_indices.begin(), entity_indices.end(), 0u);
31407  for (size_t i = 1u; i < this->entities.size(); ++i)
31408  {
31409 
31410  entity_indices[i] +=
31411  this->entities[i - 1].size() +
31412  entity_indices[i - 1]
31413  ;
31414 
31415  }
31416 
31417  // Adjusting contact rate
31418  adjusted_contact_rate.clear();
31419  adjusted_contact_rate.resize(this->entities.size(), 0.0);
31420 
31421  for (size_t i = 0u; i < this->entities.size(); ++i)
31422  {
31423 
31424  adjusted_contact_rate[i] =
31425  Model<TSeq>::get_param("Contact rate") /
31426  static_cast< epiworld_double > (this->get_entity(i).size());
31427 
31428 
31429  // Possibly correcting for a small number of agents
31430  if (adjusted_contact_rate[i] > 1.0)
31431  adjusted_contact_rate[i] = 1.0;
31432 
31433  }
31434 
31435  this->m_update_infectious_list();
31436 
31437  // Setting up the quarantine parameters
31438  quarantine_willingness.resize(this->size(), false);
31439  isolation_willingness.resize(this->size(), false);
31440  for (size_t idx = 0; idx < quarantine_willingness.size(); ++idx)
31441  {
31442  quarantine_willingness[idx] =
31443  Model<TSeq>::runif() < this->par("Quarantine willingness");
31444  isolation_willingness[idx] =
31445  Model<TSeq>::runif() < this->par("Isolation willingness");
31446  }
31447 
31448  agent_quarantine_triggered.resize(this->size(), 0u);
31449  std::fill(
31450  agent_quarantine_triggered.begin(),
31451  agent_quarantine_triggered.end(),
31452  0u
31453  );
31454 
31455  day_flagged.resize(this->size(), 0);
31456  std::fill(
31457  day_flagged.begin(),
31458  day_flagged.end(),
31459  0
31460  );
31461 
31462  day_rash_onset.resize(this->size(), 0);
31463  std::fill(
31464  day_rash_onset.begin(),
31465  day_rash_onset.end(),
31466  0
31467  );
31468 
31469  day_exposed.resize(this->size(), 0);
31470  std::fill(
31471  day_exposed.begin(),
31472  day_exposed.end(),
31473  0
31474  );
31475 
31476  // Tracking matrix
31477  tracking_matrix.resize(EPI_MAX_TRACKING * Model<TSeq>::size(), 0u);
31478  std::fill(tracking_matrix.begin(), tracking_matrix.end(), 0u);
31479 
31480  tracking_matrix_size.resize(Model<TSeq>::size(), 0u);
31481  std::fill(tracking_matrix_size.begin(), tracking_matrix_size.end(), 0u);
31482 
31483  tracking_matrix_date.resize(EPI_MAX_TRACKING * Model<TSeq>::size(), 0u);
31484  std::fill(tracking_matrix_date.begin(), tracking_matrix_date.end(), 0u);
31485 
31486  return;
31487 
31488 }
31489 
31490 template<typename TSeq>
31492 {
31493 
31495  *dynamic_cast<const ModelMeaslesMixing<TSeq>*>(this)
31496  );
31497 
31498  #if __cplusplus >= 202302L
31499  // C++23 or later
31500  [[assume(ptr != nullptr)]];
31501  #else
31502  // C++17 or C++20
31503  assert(ptr != nullptr); // Use assert for runtime checks
31504  #endif
31505 
31506  return dynamic_cast< Model<TSeq> *>(ptr);
31507 
31508 }
31509 
31510 template<typename TSeq>
31512  Agent<TSeq> * p, Model<TSeq> * m
31513 ) {
31514 
31515  if (p->get_n_entities() == 0)
31516  return;
31517 
31518  // Downcasting to retrieve the sampler attached to the
31519  // class
31520  GET_MODEL(m, m_down);
31521 
31522  size_t ndraws = m_down->sample_agents(p, m_down->sampled_agents);
31523 
31524  #ifdef EPI_DEBUG
31525  m_down->sampled_sizes.push_back(static_cast<int>(ndraws));
31526  #endif
31527 
31528  if (ndraws == 0u)
31529  return;
31530 
31531  // Drawing from the set
31532  int nviruses_tmp = 0;
31533  for (size_t n = 0u; n < ndraws; ++n)
31534  {
31535 
31536  auto & neighbor = m->get_agent(m_down->sampled_agents[n]);
31537 
31538  auto & v = neighbor.get_virus();
31539 
31540  #ifdef EPI_DEBUG
31541  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
31542  throw std::logic_error(
31543  "Trying to add an extra element to a temporal array outside of the range."
31544  );
31545  #endif
31546 
31547  // Adding the current agent to the tracked interactions
31548  m_down->m_add_tracking(neighbor.get_id(), p->get_id());
31549 
31550  /* And it is a function of susceptibility_reduction as well */
31551  m->array_double_tmp[nviruses_tmp] =
31552  (1.0 - p->get_susceptibility_reduction(v, m)) *
31553  v->get_prob_infecting(m) *
31554  (1.0 - neighbor.get_transmission_reduction(v, m))
31555  ;
31556 
31557  m->array_virus_tmp[nviruses_tmp++] = &(*v);
31558 
31559  }
31560 
31561  // Running the roulette
31562  int which = roulette(nviruses_tmp, m);
31563 
31564  if (which < 0)
31565  return;
31566 
31567  p->set_virus(
31568  *m->array_virus_tmp[which],
31569  m,
31571  );
31572 
31573  return;
31574 
31575 };
31576 
31577 template<typename TSeq>
31579  Agent<TSeq> * p, Model<TSeq> * m
31580 ) {
31581 
31582  // Getting the virus
31583  auto & v = p->get_virus();
31584 
31585  // Does the agent become prodromal (infectious)?
31586  if (m->runif() < 1.0/(v->get_incubation(m)))
31587  {
31588 
31589  p->change_state(m, ModelMeaslesMixing<TSeq>::PRODROMAL);
31590 
31591  return;
31592 
31593  }
31594 
31595  return;
31596 
31597 };
31598 
31599 template<typename TSeq>
31601  Agent<TSeq> * p, Model<TSeq> * m
31602 ) {
31603 
31604  GET_MODEL(m, model);
31605 
31606  // Does the agent transition to rash?
31607  if (m->runif() < 1.0/m->par("Prodromal period"))
31608  {
31609  model->day_rash_onset[p->get_id()] = m->today();
31610  p->change_state(m, ModelMeaslesMixing<TSeq>::RASH);
31611  }
31612 
31613  return ;
31614 
31615 };
31616 
31617 template<typename TSeq>
31619  Agent<TSeq> * p, Model<TSeq> * m
31620 ) {
31621 
31622  GET_MODEL(m, model);
31623 
31624  // Checking if the agent will be detected or not
31625  bool detected = false;
31626  if (
31627  (m->par("Isolation period") >= 0) &&
31628  (m->runif() < 1.0/m->par("Days undetected"))
31629  )
31630  {
31631  model->agent_quarantine_triggered[p->get_id()] =
31633  detected = true;
31634  }
31635 
31636  // Computing probabilities for state change
31637  m->array_double_tmp[0] = 1.0/m->par("Rash period"); // Recovery
31638  m->array_double_tmp[1] = m->par("Hospitalization rate"); // Hospitalization
31639 
31640  SAMPLE_FROM_PROBS(2, which);
31641 
31642  if (which == 2) // Recovers
31643  {
31644  p->rm_virus(
31645  m,
31646  detected ?
31649  );
31650  }
31651  else if (which == 1) // Hospitalized
31652  {
31653  p->change_state(
31654  m,
31655  detected ?
31658  );
31659  }
31660  else if (which != 0)
31661  {
31662  throw std::logic_error("The roulette returned an unexpected value.");
31663  }
31664  else if ((which == 0u) && detected)
31665  {
31666  // If the agent is not hospitalized or recovered, then it is moved to
31667  // isolation.
31668  p->change_state(m, ModelMeaslesMixing<TSeq>::ISOLATED);
31669  model->day_flagged[p->get_id()] = m->today();
31670  }
31671 
31672  return ;
31673 
31674 };
31675 
31676 template<typename TSeq>
31678  Agent<TSeq> * p, Model<TSeq> * m
31679 ) {
31680 
31681  GET_MODEL(m, model);
31682 
31683  // Figuring out if the agent can be released from isolation
31684  // if the isolation period is over.
31685  int days_since = m->today() - model->day_rash_onset[p->get_id()];
31686 
31687  bool unisolate =
31688  (m->par("Isolation period") <= days_since) ?
31689  true: false;
31690 
31691  // Sampling from the probabilities of recovery
31692  m->array_double_tmp[0] = 1.0/m->par("Rash period");
31693 
31694  // And hospitalization
31695  m->array_double_tmp[1] = m->par("Hospitalization rate");
31696 
31697  SAMPLE_FROM_PROBS(2, which);
31698 
31699  // Recovers
31700  if (which == 2)
31701  {
31702  if (unisolate)
31703  {
31704  p->rm_virus(
31705  m,
31707  );
31708  }
31709  else
31710  p->rm_virus(
31712  );
31713  }
31714  else if (which == 1)
31715  {
31716 
31717  if (unisolate)
31718  {
31719  p->change_state(
31721  );
31722  }
31723  else
31724  {
31725  p->change_state(
31727  );
31728  }
31729  }
31730  else if ((which == 0) && unisolate)
31731  {
31732  p->change_state(
31734  );
31735  }
31736 
31737 
31738 };
31739 
31740 template<typename TSeq>
31742  Agent<TSeq> * p, Model<TSeq> * m
31743 ) {
31744 
31745  GET_MODEL(m, model);
31746 
31747  // Figuring out if the agent can be released from quarantine
31748  // if the quarantine period is over.
31749  int days_since = m->today() - model->day_flagged[p->get_id()];
31750 
31751  bool unquarantine =
31752  (m->par("Quarantine period") <= days_since) ?
31753  true: false;
31754 
31755  if (unquarantine)
31756  {
31757  p->change_state(
31759  );
31760  }
31761 
31762 };
31763 
31764 template<typename TSeq>
31766  Agent<TSeq> * p, Model<TSeq> * m
31767 ) {
31768 
31769  GET_MODEL(m, model);
31770 
31771  // Figuring out if the agent can be released from quarantine
31772  // if the quarantine period is over.
31773  int days_since = m->today() - model->day_flagged[p->get_id()];
31774 
31775  bool unquarantine =
31776  (m->par("Quarantine period") <= days_since) ?
31777  true: false;
31778 
31779  if (m->runif() < 1.0/(p->get_virus()->get_incubation(m)))
31780  {
31781 
31782  // If the agent is unquarantined, it becomes prodromal
31783  if (unquarantine)
31784  {
31785  p->change_state(
31787  );
31788  }
31789  else
31790  {
31791  p->change_state(
31793  );
31794  }
31795 
31796  }
31797  else if (unquarantine)
31798  {
31799  p->change_state(
31801  );
31802  }
31803 
31804 };
31805 
31806 template<typename TSeq>
31808  Agent<TSeq> * p, Model<TSeq> * m
31809 ) {
31810 
31811  GET_MODEL(m, model);
31812 
31813  // Otherwise, these are moved to the prodromal period, if
31814  // the quarantine period is over.
31815  int days_since = m->today() - model->day_flagged[p->get_id()];
31816 
31817  bool unquarantine =
31818  (m->par("Quarantine period") <= days_since) ?
31819  true: false;
31820 
31821  // Develops rash?
31822  if (m->runif() < (1.0/m->par("Prodromal period")))
31823  {
31824  model->day_rash_onset[p->get_id()] = m->today();
31825  p->change_state(m, ModelMeaslesMixing<TSeq>::ISOLATED);
31826  }
31827  else
31828  {
31829 
31830  if (unquarantine)
31831  p->change_state(m, ModelMeaslesMixing<TSeq>::PRODROMAL);
31832 
31833  }
31834 
31835 };
31836 
31837 template<typename TSeq>
31839  Agent<TSeq> * p, Model<TSeq> * m
31840 ) {
31841 
31842  GET_MODEL(m, model);
31843  int days_since = m->today() - model->day_flagged[p->get_id()];
31844 
31845  if (days_since >= m->par("Quarantine period"))
31846  p->change_state(m, ModelMeaslesMixing<TSeq>::RECOVERED);
31847 
31848 };
31849 
31850 template<typename TSeq>
31852  Agent<TSeq> * p, Model<TSeq> * m
31853 ) {
31854 
31855  GET_MODEL(m, model);
31856 
31857  // Figuring out if the agent can be released from isolation
31858  // if the isolation period is over.
31859  int days_since = m->today() - model->day_rash_onset[p->get_id()];
31860 
31861  bool unisolate =
31862  (m->par("Isolation period") <= days_since) ?
31863  true: false;
31864 
31865  if (unisolate)
31866  {
31867  p->change_state(
31869  );
31870  }
31871 
31872 };
31873 
31874 template<typename TSeq>
31876  Agent<TSeq> * p, Model<TSeq> * m
31877 ) {
31878 
31879  // The agent is removed from the system
31880  if (m->runif() < 1.0/m->par("Hospitalization period"))
31881  p->rm_virus(m, ModelMeaslesMixing<TSeq>::RECOVERED);
31882 
31883 };
31884 
31885 template<typename TSeq>
31887 
31888  // Process entity-level quarantine
31889  for (size_t agent_i = 0u; agent_i < Model<TSeq>::size(); ++agent_i)
31890  {
31891 
31892  // Checking if the quarantine in the agent was triggered
31893  // or not
31894  if (
31895  agent_quarantine_triggered[agent_i] !=
31897  )
31898  continue;
31899 
31900  if (this->par("Quarantine period") < 0)
31901  continue;
31902 
31903  // Getting the number of contacts, if it is greater
31904  // than the maximum, it means that we overflowed, so
31905  // we will only quarantine the first EPI_MAX_TRACKING
31906  size_t n_contacts = this->tracking_matrix_size[agent_i];
31907  if (n_contacts >= EPI_MAX_TRACKING)
31908  n_contacts = EPI_MAX_TRACKING;
31909 
31910  // When the rash onset started (this is for contact tracing)
31911  size_t day_rash_onset_agent_i = this->day_rash_onset[agent_i];
31912 
31913  for (size_t contact_i = 0u; contact_i < n_contacts; ++contact_i)
31914  {
31915 
31916  // Checking if the contact is within the contact tracing days prior
31917  size_t loc = MM(agent_i, contact_i, Model<TSeq>::size());
31918  bool within_days_prior =
31919  (day_rash_onset_agent_i - tracking_matrix_date[loc]) <=
31920  Model<TSeq>::par("Contact tracing days prior");
31921  if (!within_days_prior)
31922  continue;
31923 
31924  // Checking if we will detect the contact
31925  if (Model<TSeq>::runif() > Model<TSeq>::par("Contact tracing success rate"))
31926  continue;
31927 
31928  size_t contact_id = this->tracking_matrix[loc];
31929 
31930  auto & agent = Model<TSeq>::get_agent(contact_id);
31931 
31932  if (agent.get_state() > RASH)
31933  continue;
31934 
31935  // Agents with some tool won't be quarantined
31936  if (agent.get_n_tools() != 0u)
31937  continue;
31938 
31939  if (
31940  quarantine_willingness[contact_id] &&
31941  (Model<TSeq>::par("Quarantine period") >= 0))
31942  {
31943 
31944  switch (agent.get_state())
31945  {
31946  case SUSCEPTIBLE:
31947  agent.change_state(this, QUARANTINED_SUSCEPTIBLE);
31948  day_flagged[contact_id] = Model<TSeq>::today();
31949  break;
31950  case EXPOSED:
31951  agent.change_state(this, QUARANTINED_EXPOSED);
31952  day_flagged[contact_id] = Model<TSeq>::today();
31953  break;
31954  case PRODROMAL:
31955  agent.change_state(this, QUARANTINED_PRODROMAL);
31956  day_flagged[contact_id] = Model<TSeq>::today();
31957  break;
31958  case RASH:
31959  if (isolation_willingness[contact_id])
31960  {
31961  agent.change_state(this, ISOLATED);
31962  day_flagged[contact_id] = Model<TSeq>::today();
31963  }
31964  break;
31965  default:
31966  throw std::logic_error(
31967  "The agent is not in a state that can be quarantined."
31968  );
31969  }
31970 
31971  }
31972  }
31973 
31974  // Setting the quarantine process off
31975  agent_quarantine_triggered[agent_i] =
31977  }
31978 
31979  return;
31980 }
31981 
32007 template<typename TSeq>
32009  ModelMeaslesMixing<TSeq> & model,
32010  epiworld_fast_uint n,
32011  epiworld_double prevalence,
32012  epiworld_double contact_rate,
32013  epiworld_double transmission_rate,
32014  epiworld_double vax_efficacy,
32015  epiworld_double vax_reduction_recovery_rate,
32016  epiworld_double incubation_period,
32017  epiworld_double prodromal_period,
32018  epiworld_double rash_period,
32019  std::vector< double > contact_matrix,
32020  epiworld_double hospitalization_rate,
32021  epiworld_double hospitalization_period,
32022  // Policy parameters
32023  epiworld_double days_undetected,
32024  epiworld_fast_int quarantine_period,
32025  epiworld_double quarantine_willingness,
32026  epiworld_double isolation_willingness,
32027  epiworld_fast_int isolation_period,
32028  epiworld_double prop_vaccinated,
32029  epiworld_double contact_tracing_success_rate,
32030  epiworld_fast_uint contact_tracing_days_prior
32031  )
32032 {
32033 
32034  // Setting up the contact matrix
32035  this->contact_matrix = contact_matrix;
32036 
32037  // Setting up parameters
32038  model.add_param(contact_rate, "Contact rate");
32039  model.add_param(transmission_rate, "Transmission rate");
32040  model.add_param(incubation_period, "Incubation period");
32041  model.add_param(prodromal_period, "Prodromal period");
32042  model.add_param(rash_period, "Rash period");
32043  model.add_param(hospitalization_rate, "Hospitalization rate");
32044  model.add_param(hospitalization_period, "Hospitalization period");
32045  model.add_param(days_undetected, "Days undetected");
32046  model.add_param(quarantine_period, "Quarantine period");
32047  model.add_param(
32048  quarantine_willingness, "Quarantine willingness"
32049  );
32050  model.add_param(
32051  isolation_willingness, "Isolation willingness"
32052  );
32053  model.add_param(isolation_period, "Isolation period");
32054  model.add_param(
32055  contact_tracing_success_rate, "Contact tracing success rate"
32056  );
32057  model.add_param(
32058  contact_tracing_days_prior, "Contact tracing days prior"
32059  );
32060  model.add_param(prop_vaccinated, "Vaccination rate");
32061  model.add_param(vax_efficacy, "Vax efficacy");
32062  model.add_param(vax_reduction_recovery_rate, "(IGNORED) Vax improved recovery");
32063 
32064  // state
32065  model.add_state("Susceptible", m_update_susceptible);
32066  model.add_state("Exposed", m_update_exposed);
32067  model.add_state("Prodromal", m_update_prodromal);
32068  model.add_state("Rash", m_update_rash);
32069  model.add_state("Isolated", m_update_isolated);
32070  model.add_state("Isolated Recovered", m_update_isolated_recovered);
32071  model.add_state("Detected Hospitalized", m_update_hospitalized);
32072  model.add_state("Quarantined Exposed", m_update_quarantine_exposed);
32073  model.add_state("Quarantined Susceptible", m_update_quarantine_suscep);
32074  model.add_state("Quarantined Prodromal", m_update_quarantine_prodromal);
32075  model.add_state("Quarantined Recovered", m_update_quarantine_recovered);
32076  model.add_state("Hospitalized", m_update_hospitalized);
32077  model.add_state("Recovered");
32078 
32079  // Global function
32080  model.add_globalevent(this->m_update_model, "Update infected individuals");
32081  model.queuing_off();
32082 
32083  // Preparing the virus -------------------------------------------
32084  epiworld::Virus<TSeq> virus("Measles", prevalence, true);
32085  virus.set_state(
32089  );
32090 
32091  virus.set_prob_infecting(&model("Transmission rate"));
32092  virus.set_prob_recovery(&model("Rash period"));
32093  virus.set_incubation(&model("Incubation period"));
32094 
32095  model.add_virus(virus);
32096 
32097  // Designing the vaccine
32098  Tool<> vaccine("Vaccine");
32099  vaccine.set_susceptibility_reduction(&model("Vax efficacy"));
32100  vaccine.set_recovery_enhancer(&model("(IGNORED) Vax improved recovery"));
32101  vaccine.set_distribution(
32102  distribute_tool_randomly(prop_vaccinated, true)
32103  );
32104 
32105  model.add_tool(vaccine);
32106 
32107  model.queuing_off(); // No queuing need
32108 
32109  // Adding the empty population
32110  model.agents_empty_graph(n);
32111 
32112  model.set_name("Measles with Mixing and Quarantine");
32113 
32114  return;
32115 
32116 }
32117 
32118 template<typename TSeq>
32120  epiworld_fast_uint n,
32121  epiworld_double prevalence,
32122  epiworld_double contact_rate,
32123  epiworld_double transmission_rate,
32124  epiworld_double vax_efficacy,
32125  epiworld_double vax_reduction_recovery_rate,
32126  epiworld_double incubation_period,
32127  epiworld_double prodromal_period,
32128  epiworld_double rash_period,
32129  std::vector< double > contact_matrix,
32130  epiworld_double hospitalization_rate,
32131  epiworld_double hospitalization_period,
32132  // Policy parameters
32133  epiworld_double days_undetected,
32134  epiworld_fast_int quarantine_period,
32135  epiworld_double quarantine_willingness,
32136  epiworld_double isolation_willingness,
32137  epiworld_fast_int isolation_period,
32138  epiworld_double prop_vaccinated,
32139  epiworld_double contact_tracing_success_rate,
32140  epiworld_fast_uint contact_tracing_days_prior
32141  )
32142 {
32143 
32144  this->contact_matrix = contact_matrix;
32145 
32147  *this,
32148  n,
32149  prevalence,
32150  contact_rate,
32151  transmission_rate,
32152  vax_efficacy,
32153  vax_reduction_recovery_rate,
32154  incubation_period,
32155  prodromal_period,
32156  rash_period,
32157  contact_matrix,
32158  hospitalization_rate,
32159  hospitalization_period,
32160  // Policy parameters
32161  days_undetected,
32162  quarantine_period,
32163  quarantine_willingness,
32164  isolation_willingness,
32165  isolation_period,
32166  prop_vaccinated,
32167  contact_tracing_success_rate,
32168  contact_tracing_days_prior
32169  );
32170 
32171  return;
32172 
32173 }
32174 
32175 template<typename TSeq>
32177  std::vector< double > proportions_,
32178  std::vector< int > /* queue_ */
32179 )
32180 {
32181 
32183  create_init_function_seir<TSeq>(proportions_)
32184  ;
32185 
32186  return *this;
32187 
32188 }
32189 #undef MM
32190 #undef GET_MODEL
32191 #undef SAMPLE_FROM_PROBS
32192 #endif
32193 /*//////////////////////////////////////////////////////////////////////////////
32195 
32196  End of -include/epiworld/models/measlesmixing.hpp-
32197 
32200 
32201 
32202 /*//////////////////////////////////////////////////////////////////////////////
32204 
32205  Start of -include/epiworld/models/measlesmixingriskquarantine.hpp-
32206 
32209 
32210 
32211 #ifndef EPIWORLD_MODELS_MEASLESMIXINGRISKQUARANTINE_HPP
32212 #define EPIWORLD_MODELS_MEASLESMIXINGRISKQUARANTINE_HPP
32213 
32214 #define COL_MAJOR_POS(i, j, n) \
32215  (j * n + i)
32216 
32217 #if __cplusplus >= 202302L
32218  // C++23 or later
32219  #define GET_MODEL(model, output) \
32220  auto * output = dynamic_cast< ModelMeaslesMixingRiskQuarantine<TSeq> * >( (model) ); \
32221  /*Using the [[assume(...)]] to avoid the compiler warning \
32222  if the standard is C++23 or later */ \
32223  [[assume((output) != nullptr)]];
32224 #else
32225  // C++17 or C++20
32226  #define GET_MODEL(model, output) \
32227  auto * output = dynamic_cast< ModelMeaslesMixingRiskQuarantine<TSeq> * >( (model) ); \
32228  assert((output) != nullptr); // Use assert for runtime checks
32229 #endif
32230 
32236 #define SAMPLE_FROM_PROBS(n, ans) \
32237  int ans; \
32238  epiworld_double p_total = m->runif(); \
32239  for (ans = 0; ans < static_cast<int>(n); ans++) \
32240  { \
32241  if (p_total < m->array_double_tmp[ans]) \
32242  break; \
32243  m->array_double_tmp[ans + 1] += m->array_double_tmp[ans]; \
32244  };
32245 
32270 template<typename TSeq = EPI_DEFAULT_TSEQ>
32272 {
32273 private:
32274  // Vector of vectors of infected agents (prodromal agents are infectious)
32275  std::vector< size_t > infectious;
32276 
32277  // Number of infectious agents in each group
32278  std::vector< size_t > n_infectious_per_group;
32279 
32280  // Where the agents start in the `infectious` vector
32281  std::vector< size_t > infectious_entity_indices;
32282 
32283  double m_get_risk_period(size_t agent_id);
32284 
32285  // Update the list of infectious agents
32286  void m_update_infectious_list();
32287 
32288  // Vector to hold sampled agents temporarily
32289  std::vector< size_t > sampled_agents;
32290 
32297  size_t sample_infectious_agents(
32298  Agent<TSeq> * agent,
32299  std::vector< size_t > & sampled_agents
32300  );
32301 
32302  std::vector< double > adjusted_contact_rate;
32303 
32304  // Contact matrix (column-major order)
32305  std::vector< double > contact_matrix;
32306 
32307  #ifdef EPI_DEBUG
32308  std::vector< int > sampled_sizes;
32309  #endif
32310 
32311  // Update functions
32312  static void m_update_susceptible(Agent<TSeq> * p, Model<TSeq> * m);
32313  static void m_update_exposed(Agent<TSeq> * p, Model<TSeq> * m);
32314  static void m_update_prodromal(Agent<TSeq> * p, Model<TSeq> * m);
32315  static void m_update_rash(Agent<TSeq> * p, Model<TSeq> * m);
32316  static void m_update_isolated(Agent<TSeq> * p, Model<TSeq> * m);
32317  static void m_update_isolated_recovered(Agent<TSeq> * p, Model<TSeq> * m);
32318  static void m_update_quarantine_suscep(Agent<TSeq> * p, Model<TSeq> * m);
32319  static void m_update_quarantine_exposed(Agent<TSeq> * p, Model<TSeq> * m);
32320  static void m_update_quarantine_prodromal(Agent<TSeq> * p, Model<TSeq> * m);
32321  static void m_update_quarantine_recovered(Agent<TSeq> * p, Model<TSeq> * m);
32322  static void m_update_hospitalized(Agent<TSeq> * p, Model<TSeq> * m);
32323 
32324  // Data about the quarantine process
32325  std::vector< bool > quarantine_willingness;
32326  std::vector< bool > isolation_willingness;
32327  std::vector< int > day_flagged;
32328  std::vector< int > day_rash_onset;
32329 
32330  std::vector< size_t > agents_triggered_contact_tracing;
32331  size_t agents_triggered_contact_tracing_size = 0u;
32332  std::vector< bool > agents_checked_contact_tracing;
32333 
32334  // Add an agent to the list of those that triggered contact tracing
32335  void m_add_contact_tracing(size_t agent_id);
32336 
32337  std::vector< int > quarantine_risk_level;
32338 
32339  void m_quarantine_process();
32340 
32341  static void m_update_model(Model<TSeq> * m);
32342 
32343  // We will limit tracking to up to EPI_MAX_TRACKING
32344  ContactTracing contact_tracing;
32345 
32346  std::vector< size_t > days_quarantine_triggered;
32347 
32348 public:
32349 
32350  static constexpr int SUSCEPTIBLE = 0;
32351  static constexpr int EXPOSED = 1;
32352  static constexpr int PRODROMAL = 2;
32353  static constexpr int RASH = 3;
32354  static constexpr int ISOLATED = 4;
32355  static constexpr int ISOLATED_RECOVERED = 5;
32356  static constexpr int DETECTED_HOSPITALIZED = 6;
32357  static constexpr int QUARANTINED_EXPOSED = 7;
32358  static constexpr int QUARANTINED_SUSCEPTIBLE = 8;
32359  static constexpr int QUARANTINED_PRODROMAL = 9;
32360  static constexpr int QUARANTINED_RECOVERED = 10;
32361  static constexpr int HOSPITALIZED = 11;
32362  static constexpr int RECOVERED = 12;
32363 
32364  static constexpr size_t QUARANTINE_PROCESS_INACTIVE = 0u;
32365  static constexpr size_t QUARANTINE_PROCESS_ACTIVE = 1u;
32366  static constexpr size_t QUARANTINE_PROCESS_DONE = 2u;
32367 
32368  // Risk levels for quarantine
32369  static constexpr int RISK_LOW = 0;
32370  static constexpr int RISK_MEDIUM = 1;
32371  static constexpr int RISK_HIGH = 2;
32372 
32374 
32405  epiworld_fast_uint n,
32406  epiworld_double prevalence,
32407  epiworld_double contact_rate,
32408  epiworld_double transmission_rate,
32409  epiworld_double vax_efficacy,
32410  epiworld_double incubation_period,
32411  epiworld_double prodromal_period,
32412  epiworld_double rash_period,
32413  std::vector< double > contact_matrix,
32414  epiworld_double hospitalization_rate,
32415  epiworld_double hospitalization_period,
32416  // Policy parameters
32417  epiworld_double days_undetected,
32418  epiworld_fast_int quarantine_period_high,
32419  epiworld_fast_int quarantine_period_medium,
32420  epiworld_fast_int quarantine_period_low,
32421  epiworld_double quarantine_willingness,
32422  epiworld_double isolation_willingness,
32423  epiworld_fast_int isolation_period,
32424  epiworld_double prop_vaccinated,
32425  epiworld_double detection_rate_quarantine,
32426  epiworld_double contact_tracing_success_rate = 1.0,
32427  epiworld_fast_uint contact_tracing_days_prior = 4u
32428  );
32429 
32457  epiworld_fast_uint n,
32458  epiworld_double prevalence,
32459  epiworld_double contact_rate,
32460  epiworld_double transmission_rate,
32461  epiworld_double vax_efficacy,
32462  epiworld_double incubation_period,
32463  epiworld_double prodromal_period,
32464  epiworld_double rash_period,
32465  std::vector< double > contact_matrix,
32466  epiworld_double hospitalization_rate,
32467  epiworld_double hospitalization_period,
32468  // Policy parameters
32469  epiworld_double days_undetected,
32470  epiworld_fast_int quarantine_period_high,
32471  epiworld_fast_int quarantine_period_medium,
32472  epiworld_fast_int quarantine_period_low,
32473  epiworld_double quarantine_willingness,
32474  epiworld_double isolation_willingness,
32475  epiworld_fast_int isolation_period,
32476  epiworld_double prop_vaccinated,
32477  epiworld_double detection_rate_quarantine,
32478  epiworld_double contact_tracing_success_rate = 1.0,
32479  epiworld_fast_uint contact_tracing_days_prior = 4u
32480  );
32481 
32489  epiworld_fast_uint ndays,
32490  int seed = -1
32491  );
32492 
32496  void reset();
32497 
32502  Model<TSeq> * clone_ptr();
32503 
32512  std::vector< double > proportions_,
32513  std::vector< int > queue_ = {}
32514  );
32515 
32520  void set_contact_matrix(std::vector< double > cmat)
32521  {
32522  contact_matrix = cmat;
32523  return;
32524  };
32525 
32530  auto get_contact_matrix() const
32531  {
32532  return contact_matrix;
32533  };
32534 
32540  {
32541  return quarantine_willingness;
32542  };
32543 
32549  {
32550  return isolation_willingness;
32551  };
32552 
32557  const auto & get_quarantine_risk_level() const
32558  {
32559  return quarantine_risk_level;
32560  };
32561 
32562 
32568  {
32569  return days_quarantine_triggered;
32570  };
32571 
32572 };
32573 
32574 // Implementation starts here
32575 
32576 template<typename TSeq>
32578  Model<TSeq> * m
32579 )
32580 {
32581  GET_MODEL(m, model);
32582 
32583  // This will move agents between states
32584  model->m_quarantine_process();
32585 
32586  // Updating the list of infectious agents. This is needed
32587  // for the transmission dynamics.
32588  model->m_update_infectious_list();
32589 
32590  return;
32591 }
32592 
32593 template<typename TSeq>
32594 inline double ModelMeaslesMixingRiskQuarantine<TSeq>::m_get_risk_period(size_t agent_id)
32595 {
32596 
32597  double risk_period = 0.0;
32598 
32599  // Getting the risk level
32600  int risk_level = quarantine_risk_level[agent_id];
32601 
32602  if (risk_level == RISK_HIGH)
32603  risk_period = this->par("Quarantine period high");
32604  else if (risk_level == RISK_MEDIUM)
32605  risk_period = this->par("Quarantine period medium");
32606  else
32607  risk_period = this->par("Quarantine period low");
32608 
32609  return risk_period;
32610 
32611 }
32612 
32613 template<typename TSeq>
32615 {
32616 
32617  // Getting the agents from the model
32618  auto & agents = Model<TSeq>::get_agents();
32619 
32620  // Resetting the infectious list (no infected agents)
32621  std::fill(n_infectious_per_group.begin(), n_infectious_per_group.end(), 0u);
32622 
32623  // Looping over agents to find the infectious ones
32624  for (const auto & a : agents)
32625  {
32626 
32627  if (a.get_state() == PRODROMAL)
32628  {
32629  if (a.get_n_entities() > 0u)
32630  {
32631  const auto & entity = a.get_entity(0u);
32632  infectious[
32633  // Position of the group in the `infectious` vector
32634  infectious_entity_indices[entity.get_id()] +
32635  // Position of the agent in the group
32636  n_infectious_per_group[entity.get_id()]++
32637  ] = a.get_id();
32638 
32639  }
32640  }
32641 
32642  }
32643 
32644  return;
32645 
32646 }
32647 
32648 template<typename TSeq>
32650  Agent<TSeq> * agent,
32651  std::vector< size_t > & sampled_agents
32652  )
32653 {
32654 
32655  // If agent has no entities, then we return 0
32656  if (agent->get_n_entities() == 0u)
32657  return 0u;
32658 
32659  size_t agent_group_id = agent->get_entity(0u).get_id();
32660  size_t ngroups = this->entities.size();
32661 
32662  int samp_id = 0;
32663  for (size_t g = 0; g < ngroups; ++g)
32664  {
32665 
32666  size_t group_size = n_infectious_per_group[g];
32667 
32668  if (group_size == 0u)
32669  continue;
32670 
32671  // How many from this entity?
32672  int nsamples = epiworld::Model<TSeq>::rbinom(
32673  group_size,
32674  adjusted_contact_rate[g] * contact_matrix[
32675  COL_MAJOR_POS(agent_group_id, g, ngroups)
32676  ]
32677  );
32678 
32679  if (nsamples == 0)
32680  continue;
32681 
32682  // Sampling from the entity
32683  for (int s = 0; s < nsamples; ++s)
32684  {
32685 
32686  // Randomly selecting an agent
32687  int which = epiworld::Model<TSeq>::runif() * group_size;
32688 
32689  // Correcting overflow error
32690  if (which >= static_cast<int>(group_size))
32691  which = static_cast<int>(group_size) - 1;
32692 
32693  #ifdef EPI_DEBUG
32694  auto & a = this->population.at(
32695  infectious.at(infectious_entity_indices[g] + which)
32696  );
32697  #else
32698  const auto & a = this->get_agent(
32699  infectious[infectious_entity_indices[g] + which]
32700  );
32701  #endif
32702 
32703  #ifdef EPI_DEBUG
32704  if (a.get_state() != PRODROMAL)
32705  throw std::logic_error(
32706  "The agent is not in prodromal state, but it should be."
32707  );
32708  #endif
32709 
32710  // Can't sample itself
32711  if (a.get_id() == agent->get_id())
32712  continue;
32713 
32714  sampled_agents[samp_id++] = a.get_id();
32715 
32716  }
32717 
32718  }
32719 
32720  return samp_id;
32721 
32722 }
32723 
32724 template<typename TSeq>
32726  Agent<TSeq> * p, Model<TSeq> * m
32727 ) {
32728 
32729  // If the agent has no entities, then it can't be infected
32730  // (e.g., isolated agents)
32731  if (p->get_n_entities() == 0)
32732  return;
32733 
32734  // Downcasting to retrieve the sampler attached to the
32735  // class
32736  GET_MODEL(m, m_down);
32737 
32738  // Sampling infected agents
32739  size_t ndraws = m_down->sample_infectious_agents(p, m_down->sampled_agents);
32740 
32741  #ifdef EPI_DEBUG
32742  m_down->sampled_sizes.push_back(static_cast<int>(ndraws));
32743  #endif
32744 
32745  if (ndraws == 0u)
32746  return;
32747 
32748  // Drawing from the set
32749  int nviruses_tmp = 0;
32750  for (size_t n = 0u; n < ndraws; ++n)
32751  {
32752 
32753  // Getting the neighbor and its virus
32754  auto & neighbor = m->get_agent(m_down->sampled_agents[n]);
32755  auto & v = neighbor.get_virus();
32756 
32757  #ifdef EPI_DEBUG
32758  if (nviruses_tmp >= static_cast<int>(m->array_virus_tmp.size()))
32759  throw std::logic_error(
32760  "Trying to add an extra element to a temporal array outside of the range."
32761  );
32762  #endif
32763 
32764  // Adding the current agent to the tracked interactions
32765  // In this case, the infected neighbor is the one
32766  // who interacts with the susceptible agent
32767  m_down->contact_tracing.add_contact(neighbor.get_id(), p->get_id(), m->today());
32768 
32769  /* And it is a function of susceptibility_reduction as well */
32770  m->array_double_tmp[nviruses_tmp] =
32771  (1.0 - p->get_susceptibility_reduction(v, m)) *
32772  v->get_prob_infecting(m) *
32773  (1.0 - neighbor.get_transmission_reduction(v, m))
32774  ;
32775 
32776  m->array_virus_tmp[nviruses_tmp++] = &(*v);
32777 
32778  }
32779 
32780  // Running the roulette
32781  int which = roulette(nviruses_tmp, m);
32782 
32783  if (which < 0)
32784  return;
32785 
32786  p->set_virus(*m->array_virus_tmp[which], m, EXPOSED);
32787 
32788  return;
32789 
32790 }
32791 
32792 template<typename TSeq>
32794  Agent<TSeq> * p, Model<TSeq> * m
32795 ) {
32796 
32797  // Getting the virus
32798  auto & v = p->get_virus();
32799 
32800  // Does the agent become prodromal (infectious)?
32801  if (m->runif() < 1.0/(v->get_incubation(m)))
32802  {
32803  p->change_state(m, PRODROMAL);
32804  }
32805 
32806 }
32807 
32808 template<typename TSeq>
32810  Agent<TSeq> * p, Model<TSeq> * m
32811 ) {
32812 
32813  GET_MODEL(m, model);
32814 
32815  // Does the agent transition to rash?
32816  if (m->runif() < 1.0/m->par("Prodromal period"))
32817  {
32818  // Check for detection during active quarantine
32819  bool detect_it = (model->get_days_quarantine_triggered().size() > 0u) &&
32820  (m->runif() < m->par("Detection rate quarantine"));
32821 
32822  model->day_rash_onset[p->get_id()] = m->today();
32823  p->change_state(m, detect_it ? ISOLATED : RASH);
32824 
32825  if (detect_it)
32826  model->m_add_contact_tracing(p->get_id());
32827 
32828  }
32829 
32830  return ;
32831 
32832 }
32833 
32834 template<typename TSeq>
32836  Agent<TSeq> * p, Model<TSeq> * m
32837 ) {
32838 
32839  GET_MODEL(m, model);
32840 
32841  // Checking if the agent will be detected or not
32842  bool detected = false;
32843  if (
32844  (m->par("Isolation period") >= 0) &&
32845  (m->runif() < 1.0/m->par("Days undetected"))
32846  )
32847  {
32848  model->m_add_contact_tracing(p->get_id());
32849  detected = true;
32850  model->day_flagged[p->get_id()] = m->today();
32851  }
32852 
32853  // Computing probabilities for state change
32854  m->array_double_tmp[0] = 1.0/m->par("Rash period"); // Recovery
32855  m->array_double_tmp[1] = m->par("Hospitalization rate"); // Hospitalization
32856 
32857  SAMPLE_FROM_PROBS(2, which);
32858 
32859  if (which == 2) // Recovers
32860  {
32861  p->rm_virus(m, detected ? ISOLATED_RECOVERED: RECOVERED);
32862  }
32863  else if (which == 1) // Hospitalized
32864  {
32865  p->change_state(m, detected ? DETECTED_HOSPITALIZED : HOSPITALIZED);
32866  }
32867  else if ((which == 0) && detected)
32868  {
32869  p->change_state(m, ISOLATED);
32870  }
32871  else if (which != 0)
32872  {
32873  throw std::logic_error("The roulette returned an unexpected value.");
32874  }
32875 
32876  return ;
32877 
32878 }
32879 
32880 template<typename TSeq>
32882  Agent<TSeq> * p, Model<TSeq> * m
32883 ) {
32884 
32885  GET_MODEL(m, model);
32886 
32887  // Figuring out if the agent can be released from isolation
32888  // if the isolation period is over.
32889  int days_since = m->today() - model->day_rash_onset[p->get_id()];
32890 
32891  bool unisolate =
32892  (m->par("Isolation period") <= days_since) ?
32893  true: false;
32894 
32895  // Probability of staying in the rash period vs becoming
32896  // hospitalized
32897  m->array_double_tmp[0] = 1.0/m->par("Rash period");
32898  m->array_double_tmp[1] = m->par("Hospitalization rate");
32899 
32900  // Sampling from the probabilities
32901  SAMPLE_FROM_PROBS(2, which);
32902 
32903  // Recovers
32904  if (which == 2u)
32905  {
32906  p->rm_virus(m, unisolate ? RECOVERED : ISOLATED_RECOVERED);
32907  }
32908  // Moves to hospitalized
32909  else if (which == 1u)
32910  {
32911  p->change_state(m, DETECTED_HOSPITALIZED);
32912  }
32913  // Stays in rash, may or may not be released from isolation
32914  else if ((which == 0u) && unisolate)
32915  {
32916  p->change_state(m, RASH);
32917  }
32918 
32919 
32920 }
32921 
32922 template<typename TSeq>
32924  Agent<TSeq> * p,
32925  Model<TSeq> * m
32926 ) {
32927 
32928  GET_MODEL(m, model);
32929 
32930  // Figuring out if the agent can be released from isolation
32931  // if the isolation period is over.
32932  int days_since = m->today() - model->day_rash_onset[p->get_id()];
32933 
32934  if (m->par("Isolation period") <= days_since)
32935  p->change_state(m, RECOVERED);
32936 
32937 }
32938 
32939 template<typename TSeq>
32941  Agent<TSeq> * p,
32942  Model<TSeq> * m
32943 ) {
32944 
32945  GET_MODEL(m, model);
32946 
32947  // Get the appropriate quarantine period based on risk level
32948  auto quarantine_period = model->m_get_risk_period(p->get_id());
32949 
32950  // Figuring out if the agent can be released from quarantine
32951  int days_since = m->today() - model->day_flagged[p->get_id()];
32952 
32953  if (quarantine_period <= days_since)
32954  p->change_state(m, SUSCEPTIBLE);
32955 
32956 }
32957 
32958 template<typename TSeq>
32960  Agent<TSeq> * p,
32961  Model<TSeq> * m
32962 ) {
32963 
32964  GET_MODEL(m, model);
32965 
32966  // Get the appropriate quarantine period based on risk level
32967  auto quarantine_period = model->m_get_risk_period(p->get_id());
32968 
32969  // Figuring out if the agent can be released from quarantine
32970  int days_since = m->today() - model->day_flagged[p->get_id()];
32971 
32972  // Probability of moving to prodromal
32973  if (m->runif() < 1.0/(p->get_virus()->get_incubation(m)))
32974  {
32975 
32976  // If the agent is unquarantined, it becomes prodromal
32977  p->change_state(
32978  m,
32979  (quarantine_period <= days_since) ?
32980  PRODROMAL : QUARANTINED_PRODROMAL
32981  );
32982 
32983 
32984  }
32985  else if (quarantine_period <= days_since)
32986  {
32987  p->change_state(m, EXPOSED);
32988  }
32989 
32990 }
32991 
32992 template<typename TSeq>
32994  Agent<TSeq> * p,
32995  Model<TSeq> * m
32996 ) {
32997 
32998  GET_MODEL(m, model);
32999 
33000  // Get the appropriate quarantine period based on risk level
33001  auto quarantine_period = model->m_get_risk_period(p->get_id());
33002 
33003  // Figuring out if the agent can be released from quarantine
33004  int days_since = m->today() - model->day_flagged[p->get_id()];
33005 
33006  // Develops rash?
33007  if (m->runif() < (1.0/m->par("Prodromal period")))
33008  {
33009 
33010  // Developing Rash automatically triggers contact tracing
33011  model->m_add_contact_tracing(p->get_id());
33012 
33013  model->day_rash_onset[p->get_id()] = m->today();
33014  p->change_state(m, ISOLATED);
33015 
33016  }
33017  else if (quarantine_period <= days_since)
33018  {
33019  p->change_state(m, PRODROMAL);
33020 
33021  }
33022 
33023 }
33024 
33025 template<typename TSeq>
33027  Agent<TSeq> * p,
33028  Model<TSeq> * m
33029 ) {
33030 
33031  GET_MODEL(m, model);
33032 
33033  // Get the appropriate quarantine period based on risk level
33034  auto quarantine_period = model->m_get_risk_period(p->get_id());
33035 
33036  // Figuring out if the agent can be released from quarantine
33037  int days_since = m->today() - model->day_flagged[p->get_id()];
33038 
33039  if (quarantine_period <= days_since)
33040  p->change_state(m, RECOVERED);
33041 
33042 }
33043 
33044 template<typename TSeq>
33046  Agent<TSeq> * p,
33047  Model<TSeq> * m
33048 ) {
33049 
33050  // The agent is removed from the system
33051  if (m->runif() < 1.0/m->par("Hospitalization period"))
33052  p->rm_virus(m, RECOVERED);
33053 
33054 };
33055 
33056 template<typename TSeq>
33058 
33059  this->agents_triggered_contact_tracing[
33060  this->agents_triggered_contact_tracing_size++
33061  ] = agent_id;
33062 
33063  return;
33064 
33065 }
33066 
33067 template<typename TSeq>
33069 
33070  // If no agents triggered contact tracing, then we skip
33071  if (agents_triggered_contact_tracing_size == 0u)
33072  return;
33073 
33074  // We increase the number of quarantines
33075  days_quarantine_triggered.push_back(Model<TSeq>::today());
33076 
33077  // This vector indicates whether an agent can be quarantined
33078  // (i.e., is not already in quarantine or isolation)
33079  std::vector< bool > can_quarantine(
33080  Model<TSeq>::size(), false
33081  );
33082 
33083  // Assigning all individuals who are not currently in quarantine/isolation
33084  // a low level
33085  for (auto & agent: Model<TSeq>::get_agents())
33086  {
33087 
33088  auto state = agent.get_state();
33089 
33090  if (
33091  (state == SUSCEPTIBLE) ||
33092  (state == EXPOSED) ||
33093  (state == PRODROMAL) ||
33094  (state == RASH)
33095  )
33096  {
33097  quarantine_risk_level[agent.get_id()] = RISK_LOW;
33098  can_quarantine[agent.get_id()] = true;
33099  }
33100 
33101  }
33102 
33103  #ifdef EPI_DEBUG
33104  std::map< std::pair<size_t, size_t>, bool> success_contact;
33105  #endif
33106 
33107  // Checking the risk levels
33108  double param_days_prior = Model<TSeq>::par("Contact tracing days prior");
33109  for (size_t i = 0u; i < agents_triggered_contact_tracing_size; ++i)
33110  {
33111 
33112  size_t agent_i_idx = agents_triggered_contact_tracing[i];
33113  auto & agent_i = Model<TSeq>::get_agent(agent_i_idx);
33114 
33115  // (A) Checking entity first
33116  // It doesn't matter if the agent doesn't have a tool; we will
33117  // check that later
33118  if (agent_i.get_n_entities() != 0u)
33119  {
33120  for (auto & agent_j_idx: agent_i.get_entity(0))
33121  {
33122 
33123  #ifdef EPI_DEBUG
33124  auto & agent_j = Model<TSeq>::get_agent(agent_j_idx);
33125  if (
33126  agent_j.get_entity(0u).get_id() !=
33127  agent_i.get_entity(0u).get_id()
33128  )
33129  throw std::logic_error(
33130  "An agent in a group has a different group id."
33131  );
33132  #endif
33133 
33134 
33135  // Only if not already checked we set to high risk
33136  if (can_quarantine[agent_j_idx])
33137  quarantine_risk_level[agent_j_idx] = RISK_HIGH;
33138 
33139 
33140  }
33141  }
33142 
33143  // (B) Checking the contacts
33144  size_t n_contacts = contact_tracing.get_n_contacts(agent_i_idx);
33145  if (n_contacts > EPI_MAX_TRACKING)
33146  n_contacts = EPI_MAX_TRACKING;
33147 
33148  for (size_t contact_j_idx = 0u; contact_j_idx < n_contacts; ++contact_j_idx)
33149  {
33150 
33151  // Getting the location in the matrix
33152  auto [contact_id, contact_date] = contact_tracing.get_contact(
33153  agent_i_idx, contact_j_idx
33154  );
33155 
33156  // Checked agents should not be considered
33157  if (!can_quarantine[contact_id])
33158  continue;
33159 
33160  // Will we detect the contact?
33161  if (
33162  Model<TSeq>::runif() >
33163  Model<TSeq>::par("Contact tracing success rate")
33164  )
33165  continue;
33166 
33167  // How many days since they contacted relative to the rash onset?
33168  // (recall that, in this model, the rash period is not infectious)
33169  double days_since_contact =
33170  static_cast<double>(this->day_rash_onset[agent_i_idx]) -
33171  static_cast<double>(contact_date);
33172 
33173  // If the contact is outside of the tracing window, we skip it
33174  if (days_since_contact > param_days_prior)
33175  continue;
33176 
33177  #ifdef EPI_DEBUG
33178  auto pair = std::make_pair(agent_i_idx, contact_id);
33179  success_contact[pair] = true;
33180  #endif
33181 
33182  // Setting the risk level to medium if not already high
33183  if (quarantine_risk_level[contact_id] < RISK_HIGH)
33184  quarantine_risk_level[contact_id] = RISK_MEDIUM;
33185 
33186  }
33187 
33188  }
33189 
33190  // Proceeding to quarantine/isolating agents
33191  for (auto & agent: Model<TSeq>::get_agents())
33192  {
33193 
33194  // Only if not already checked
33195  if (!can_quarantine[agent.get_id()])
33196  continue;
33197 
33198  // If has a tool, then skip (is vaxxed)
33199  if (agent.get_n_tools() != 0u)
33200  continue;
33201 
33202  if (quarantine_willingness[agent.get_id()] == false)
33203  continue;
33204 
33205  // Setting the day flagged to today
33206  day_flagged[agent.get_id()] = Model<TSeq>::today();
33207 
33208  auto state = agent.get_state();
33209  if (state == SUSCEPTIBLE)
33210  agent.change_state(this, QUARANTINED_SUSCEPTIBLE);
33211  else if (state == EXPOSED)
33212  agent.change_state(this, QUARANTINED_EXPOSED);
33213  else if (state == PRODROMAL)
33214  agent.change_state(this, QUARANTINED_PRODROMAL);
33215  else if (state == RASH)
33216  {
33217  if (isolation_willingness[agent.get_id()])
33218  agent.change_state(this, ISOLATED);
33219  }
33220  else
33221  throw std::logic_error(
33222  "An agent in an unexpected state is being quarantined."
33223  );
33224  }
33225 
33226  #ifdef EPI_DEBUG
33227  // Agents in groups that triggered the quarantine level, who are not
33228  // quarantined should be in RISK_HIGH
33229  std::set< size_t > groups_ids;
33230  std::set< size_t > contacted_agents;
33231  for (size_t i = 0u; i < agents_triggered_contact_tracing_size; ++i)
33232  {
33233 
33234  auto agent_i_idx = agents_triggered_contact_tracing[i];
33235 
33236  auto & agent_i = Model<TSeq>::get_agent(agent_i_idx);
33237 
33238  // We also check who are the contacted agents
33239  size_t n_contacts = contact_tracing.get_n_contacts(agent_i_idx);
33240  if (n_contacts >= EPI_MAX_TRACKING)
33241  n_contacts = EPI_MAX_TRACKING;
33242 
33243  for (size_t contact_j_idx = 0u; contact_j_idx < n_contacts; ++contact_j_idx)
33244  {
33245 
33246  // Getting the location in the matrix
33247  auto [contact_id, contact_date] = contact_tracing.get_contact(
33248  agent_i_idx, contact_j_idx
33249  );
33250 
33251  // Was the contact successful?
33252  auto pair = std::make_pair(agent_i_idx, contact_id);
33253  if (!success_contact[pair])
33254  continue;
33255 
33256  contacted_agents.insert(contact_id);
33257  }
33258 
33259  if (agent_i.get_n_entities() == 0u)
33260  continue;
33261 
33262  groups_ids.insert(agent_i.get_entity(0u).get_id());
33263 
33264  }
33265 
33266  // Iterating over the agents in those groups, if they in the states
33267  // SUSCEPTIBLE, EXPOSED, PRODROMAL, or RASH, they should be in
33268  // RISK_HIGH
33269  for (auto & group: groups_ids)
33270  {
33271  for (auto & agent_i_idx: Model<TSeq>::get_entity(group))
33272  {
33273 
33274  auto & agent_i = Model<TSeq>::get_agent(agent_i_idx);
33275  auto state = agent_i.get_state();
33276 
33277  // If not in any of these states, we skip
33278  if (
33279  (state != SUSCEPTIBLE) &&
33280  (state != EXPOSED) &&
33281  (state != PRODROMAL) &&
33282  (state != RASH)
33283  )
33284  continue;
33285 
33286  // If has a tool, then skip (is vaxxed)
33287  if (agent_i.get_n_tools() != 0u)
33288  continue;
33289 
33290  if (quarantine_risk_level[agent_i_idx] != RISK_HIGH)
33291  throw std::logic_error(
33292  "An agent in a group that triggered contact tracing is not in RISK_HIGH."
33293  );
33294 
33295  }
33296  }
33297 
33298  // Now, agents who were not members of the groups that triggered
33299  // contact tracing, but were contacted by them should be at least
33300  // in RISK_MEDIUM
33301  for (auto & agent_i_idx: contacted_agents)
33302  {
33303  auto & agent_i = Model<TSeq>::get_agent(agent_i_idx);
33304  auto state = agent_i.get_state();
33305 
33306  // If has a tool, then skip (is vaxxed)
33307  if (agent_i.get_n_tools() != 0u)
33308  continue;
33309 
33310  // Checking the agent is not in a group that triggered
33311  // contact tracing
33312  if (agent_i.get_n_entities() != 0u)
33313  {
33314  size_t group_id = agent_i.get_entity(0u).get_id();
33315  if (groups_ids.find(group_id) != groups_ids.end())
33316  continue;
33317  }
33318 
33319  if (quarantine_risk_level[agent_i_idx] != RISK_MEDIUM)
33320  throw std::logic_error(
33321  "An agent who was contacted by an infectious agent is not in at least RISK_MEDIUM."
33322  );
33323  }
33324 
33325  // Tabulating the number of agents per group
33326  std::vector< size_t > n_agents_per_group(Model<TSeq>::entities.size(), 0u);
33327  for (auto i: quarantine_risk_level)
33328  n_agents_per_group[i]++;
33329 
33330  #endif
33331 
33332  // Applying the changes and resetting the number of agents
33333  // who triggered contact tracing
33335  agents_triggered_contact_tracing_size = 0u;
33336 
33337  return;
33338 }
33339 
33340 template<typename TSeq>
33343  epiworld_fast_uint n,
33344  epiworld_double prevalence,
33345  epiworld_double contact_rate,
33346  epiworld_double transmission_rate,
33347  epiworld_double vax_efficacy,
33348  epiworld_double incubation_period,
33349  epiworld_double prodromal_period,
33350  epiworld_double rash_period,
33351  std::vector< double > contact_matrix,
33352  epiworld_double hospitalization_rate,
33353  epiworld_double hospitalization_period,
33354  // Policy parameters
33355  epiworld_double days_undetected,
33356  epiworld_fast_int quarantine_period_high,
33357  epiworld_fast_int quarantine_period_medium,
33358  epiworld_fast_int quarantine_period_low,
33359  epiworld_double quarantine_willingness,
33360  epiworld_double isolation_willingness,
33361  epiworld_fast_int isolation_period,
33362  epiworld_double prop_vaccinated,
33363  epiworld_double detection_rate_quarantine,
33364  epiworld_double contact_tracing_success_rate,
33365  epiworld_fast_uint contact_tracing_days_prior
33366  )
33367 {
33368 
33369  // Setting up the contact matrix
33370  this->contact_matrix = contact_matrix;
33371 
33372  // Setting up parameters
33373  model.add_param(contact_rate, "Contact rate");
33374  model.add_param(transmission_rate, "Transmission rate");
33375  model.add_param(incubation_period, "Incubation period");
33376  model.add_param(prodromal_period, "Prodromal period");
33377  model.add_param(rash_period, "Rash period");
33378  model.add_param(hospitalization_rate, "Hospitalization rate");
33379  model.add_param(hospitalization_period, "Hospitalization period");
33380  model.add_param(days_undetected, "Days undetected");
33381  model.add_param(quarantine_period_high, "Quarantine period high");
33382  model.add_param(quarantine_period_medium, "Quarantine period medium");
33383  model.add_param(quarantine_period_low, "Quarantine period low");
33384  model.add_param(
33385  quarantine_willingness, "Quarantine willingness"
33386  );
33387  model.add_param(
33388  isolation_willingness, "Isolation willingness"
33389  );
33390  model.add_param(isolation_period, "Isolation period");
33391  model.add_param(detection_rate_quarantine, "Detection rate quarantine");
33392  model.add_param(
33393  contact_tracing_success_rate, "Contact tracing success rate"
33394  );
33395  model.add_param(
33396  contact_tracing_days_prior, "Contact tracing days prior"
33397  );
33398  model.add_param(prop_vaccinated, "Vaccination rate");
33399  model.add_param(vax_efficacy, "Vax efficacy");
33400 
33401  // state
33402  model.add_state("Susceptible", m_update_susceptible);
33403  model.add_state("Exposed", m_update_exposed);
33404  model.add_state("Prodromal", m_update_prodromal);
33405  model.add_state("Rash", m_update_rash);
33406  model.add_state("Isolated", m_update_isolated);
33407  model.add_state("Isolated Recovered", m_update_isolated_recovered);
33408  model.add_state("Detected Hospitalized", m_update_hospitalized);
33409  model.add_state("Quarantined Exposed", m_update_quarantine_exposed);
33410  model.add_state("Quarantined Susceptible", m_update_quarantine_suscep);
33411  model.add_state("Quarantined Prodromal", m_update_quarantine_prodromal);
33412  model.add_state("Quarantined Recovered", m_update_quarantine_recovered);
33413  model.add_state("Hospitalized", m_update_hospitalized);
33414  model.add_state("Recovered");
33415 
33416  // Global function
33417  model.add_globalevent(this->m_update_model, "Update infected individuals");
33418  model.queuing_off();
33419 
33420  // Preparing the virus -------------------------------------------
33421  epiworld::Virus<TSeq> virus("Measles", prevalence, true);
33422  virus.set_state(
33426  );
33427 
33428  virus.set_prob_infecting(&model("Transmission rate"));
33429  virus.set_prob_recovery(&model("Rash period"));
33430  virus.set_incubation(&model("Incubation period"));
33431 
33432  model.add_virus(virus);
33433 
33434  // Designing the vaccine
33435  Tool<> vaccine("Vaccine");
33436  vaccine.set_susceptibility_reduction(&model("Vax efficacy"));
33437  vaccine.set_distribution(
33438  distribute_tool_randomly(prop_vaccinated, true)
33439  );
33440 
33441  model.add_tool(vaccine);
33442 
33443  model.queuing_off(); // No queuing need
33444 
33445  // Adding the empty population
33446  model.agents_empty_graph(n);
33447 
33448  model.set_name("Measles with Mixing and Risk-based Quarantine");
33449 
33450  return;
33451 
33452 }
33453 
33454 template<typename TSeq>
33456  epiworld_fast_uint n,
33457  epiworld_double prevalence,
33458  epiworld_double contact_rate,
33459  epiworld_double transmission_rate,
33460  epiworld_double vax_efficacy,
33461  epiworld_double incubation_period,
33462  epiworld_double prodromal_period,
33463  epiworld_double rash_period,
33464  std::vector< double > contact_matrix,
33465  epiworld_double hospitalization_rate,
33466  epiworld_double hospitalization_period,
33467  // Policy parameters
33468  epiworld_double days_undetected,
33469  epiworld_fast_int quarantine_period_high,
33470  epiworld_fast_int quarantine_period_medium,
33471  epiworld_fast_int quarantine_period_low,
33472  epiworld_double quarantine_willingness,
33473  epiworld_double isolation_willingness,
33474  epiworld_fast_int isolation_period,
33475  epiworld_double prop_vaccinated,
33476  epiworld_double detection_rate_quarantine,
33477  epiworld_double contact_tracing_success_rate,
33478  epiworld_fast_uint contact_tracing_days_prior
33480  *this,
33481  n,
33482  prevalence,
33483  contact_rate,
33484  transmission_rate,
33485  vax_efficacy,
33486  incubation_period,
33487  prodromal_period,
33488  rash_period,
33489  contact_matrix,
33490  hospitalization_rate,
33491  hospitalization_period,
33492  // Policy parameters
33493  days_undetected,
33494  quarantine_period_high,
33495  quarantine_period_medium,
33496  quarantine_period_low,
33497  quarantine_willingness,
33498  isolation_willingness,
33499  isolation_period,
33500  prop_vaccinated,
33501  detection_rate_quarantine,
33502  contact_tracing_success_rate,
33503  contact_tracing_days_prior
33504  ) {};
33505 
33506 template<typename TSeq>
33508  epiworld_fast_uint ndays,
33509  int seed
33510 )
33511 {
33512  Model<TSeq>::run(ndays, seed);
33513  return *this;
33514 }
33515 
33516 template<typename TSeq>
33518 {
33519 
33521 
33522  // Checking contact matrix's rows add to one
33523  size_t nentities = this->entities.size();
33524  if (this->contact_matrix.size() != nentities*nentities)
33525  throw std::length_error(
33526  std::string("The contact matrix must be a square matrix of size ") +
33527  std::string("nentities x nentities. ") +
33528  std::to_string(this->contact_matrix.size()) +
33529  std::string(" != ") + std::to_string(nentities*nentities) +
33530  std::string(".")
33531  );
33532 
33533  for (size_t i = 0u; i < this->entities.size(); ++i)
33534  {
33535  double sum = 0.0;
33536  for (size_t j = 0u; j < this->entities.size(); ++j)
33537  {
33538  if (this->contact_matrix[COL_MAJOR_POS(i, j, nentities)] < 0.0)
33539  throw std::range_error(
33540  std::string("The contact matrix must be non-negative. ") +
33541  std::to_string(this->contact_matrix[COL_MAJOR_POS(i, j, nentities)]) +
33542  std::string(" < 0.")
33543  );
33544  sum += this->contact_matrix[COL_MAJOR_POS(i, j, nentities)];
33545  }
33546  if (sum < 0.999 || sum > 1.001)
33547  throw std::range_error(
33548  std::string("The contact matrix must have rows that add to one. ") +
33549  std::to_string(sum) +
33550  std::string(" != 1.")
33551  );
33552  }
33553 
33554  // Do it the first time only
33555  sampled_agents.resize(Model<TSeq>::size());
33556 
33557  // We only do it once
33558  n_infectious_per_group.assign(this->entities.size(), 0u);
33559 
33560  // We are assuming one agent per entity
33561  infectious.assign(Model<TSeq>::size(), 0u);
33562 
33563  // This will say when do the groups start in the `infectious` vector
33564  infectious_entity_indices.assign(this->entities.size(), 0u);
33565  for (size_t i = 1u; i < this->entities.size(); ++i)
33566  {
33567 
33568  infectious_entity_indices[i] +=
33569  this->entities[i - 1].size() +
33570  infectious_entity_indices[i - 1]
33571  ;
33572 
33573  }
33574 
33575  // Adjusting contact rate
33576  adjusted_contact_rate.assign(this->entities.size(), 0.0);
33577 
33578  for (size_t i = 0u; i < this->entities.size(); ++i)
33579  {
33580 
33581  adjusted_contact_rate[i] =
33582  Model<TSeq>::get_param("Contact rate") /
33583  static_cast< epiworld_double > (this->get_entity(i).size());
33584 
33585 
33586  // Possibly correcting for a small number of agents
33587  if (adjusted_contact_rate[i] > 1.0)
33588  adjusted_contact_rate[i] = 1.0;
33589 
33590  }
33591 
33592  this->m_update_infectious_list();
33593 
33594  // Setting up the quarantine parameters
33595  quarantine_willingness.resize(this->size(), false);
33596  isolation_willingness.resize(this->size(), false);
33597  for (size_t idx = 0; idx < quarantine_willingness.size(); ++idx)
33598  {
33599  quarantine_willingness[idx] =
33600  Model<TSeq>::runif() < this->par("Quarantine willingness");
33601  isolation_willingness[idx] =
33602  Model<TSeq>::runif() < this->par("Isolation willingness");
33603  }
33604 
33605  day_flagged.assign(this->size(), 0);
33606  day_rash_onset.assign(this->size(), 0);
33607 
33608  // Variables about contact tracing
33609  agents_triggered_contact_tracing.assign(Model<TSeq>::size(), 0u);
33610  agents_triggered_contact_tracing_size = 0u;
33611  agents_checked_contact_tracing.assign(this->size(), false);
33612 
33613  quarantine_risk_level.assign(this->size(), RISK_LOW);
33614 
33615  // Setting up contact tracking matrix
33616  contact_tracing.reset(
33617  this->size(),
33618  EPI_MAX_TRACKING
33619  );
33620 
33621  // Resetting the number of quarantines
33622  days_quarantine_triggered.clear();
33623 
33624  return;
33625 
33626 }
33627 
33628 template<typename TSeq>
33630 {
33631 
33633  *dynamic_cast<const ModelMeaslesMixingRiskQuarantine<TSeq>*>(this)
33634  );
33635 
33636  return dynamic_cast< Model<TSeq> *>(ptr);
33637 
33638 }
33639 
33640 template<typename TSeq>
33642  std::vector< double > proportions_,
33643  std::vector< int > /* queue_ */
33644 )
33645 {
33646 
33648  create_init_function_seir<TSeq>(proportions_)
33649  ;
33650 
33651  return *this;
33652 
33653 }
33654 
33655 #undef SAMPLE_FROM_PROBS
33656 #undef GET_MODEL
33657 
33658 #endif
33659 /*//////////////////////////////////////////////////////////////////////////////
33661 
33662  End of -include/epiworld/models/measlesmixingriskquarantine.hpp-
33663 
33666 
33667 
33668 
33669 
33670 }
33671 
33672 #endif
33673 /*//////////////////////////////////////////////////////////////////////////////
33675 
33676  End of -include/epiworld/models/models.hpp-
33677 
33680 
33681 
33682 
33683 }
33684 
33685 #endif
Definition: adjlist-bones.hpp:4
size_t vcount() const
Number of vertices/nodes in the network.
Definition: adjlist-meat.hpp:203
void read_edgelist(std::string fn, int size, int skip=0, bool directed=true)
Read an edgelist.
Definition: adjlist-meat.hpp:92
Agent (agents)
Definition: agent-bones.hpp:66
double & operator()(size_t j)
Access the j-th column of the agent.
Definition: agent-meat.hpp:836
int get_id() const
Id of the individual.
Definition: agent-meat.hpp:465
void rm_agent_by_virus(Model< TSeq > *model)
Agent removed by virus.
Definition: agent-meat.hpp:417
void swap_neighbors(Agent< TSeq > &other, size_t n_this, size_t n_other)
Swaps neighbors between the current agent and agent other
Definition: agent-meat.hpp:584
Statistical data about the process.
Definition: database-bones.hpp:34
Set of Entities (const) (useful for iterators)
Definition: entities-bones.hpp:116
Set of Entities (useful for building iterators)
Definition: entities-bones.hpp:17
Definition: entity-bones.hpp:20
Template for a Global Event.
Definition: globalevent-bones.hpp:15
Template for a Network Diffusion Model.
Definition: diffnet.hpp:15
Core class of epiworld.
Definition: model-bones.hpp:91
std::vector< Agent< TSeq > > & get_agents()
Returns a reference to the vector of agents.
Definition: model-meat.hpp:582
void run_multiple(epiworld_fast_uint ndays, epiworld_fast_uint nexperiments, int seed_=-1, std::function< void(size_t, Model< TSeq > *)> fun=make_save_run< TSeq >(), bool reset=true, bool verbose=true, int nthreads=1)
Definition: model-meat.hpp:1477
void load_agents_entities_ties(std::string fn, int skip)
Associate agents-entities from a file.
Definition: model-meat.hpp:1088
size_t get_n_tools() const
Number of tools in the model.
Definition: model-meat.hpp:1767
void write_data(std::string fn_virus_info, std::string fn_virus_hist, std::string fn_tool_info, std::string fn_tool_hist, std::string fn_total_hist, std::string fn_transmission, std::string fn_transition, std::string fn_reproductive_number, std::string fn_generation_time) const
Wrapper of DataBase::write_data
Definition: model-meat.hpp:1843
void events_run()
Executes the stored action.
Definition: model-meat.hpp:219
virtual void reset()
Reset the model.
Definition: model-meat.hpp:1962
int today() const
The current time of the model.
Definition: model-meat.hpp:1316
virtual Model< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Runs the simulation (after initialization)
Definition: model-meat.hpp:1366
size_t get_n_viruses() const
Number of viruses in the model.
Definition: model-meat.hpp:1762
Measles model with population mixing, quarantine, and contact tracing.
Definition: measlesmixing.hpp:72
ModelMeaslesMixing< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: measlesmixing.hpp:1302
ModelMeaslesMixing< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Run the model simulation.
Definition: measlesmixing.hpp:469
Model< TSeq > * clone_ptr()
Create a clone of this model.
Definition: measlesmixing.hpp:617
void reset()
Reset the model to initial state.
Definition: measlesmixing.hpp:482
Measles model with population mixing and risk-based quarantine strategies.
Definition: measlesmixingriskquarantine.hpp:62
void reset()
Reset the model to initial state.
Definition: measlesmixingriskquarantine.hpp:1307
ModelMeaslesMixingRiskQuarantine< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Run the model simulation.
Definition: measlesmixingriskquarantine.hpp:1297
ModelMeaslesMixingRiskQuarantine< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: measlesmixingriskquarantine.hpp:1431
Model< TSeq > * clone_ptr()
Create a clone of this model.
Definition: measlesmixingriskquarantine.hpp:1419
Template for a Measles model with quarantine.
Definition: measlesschool.hpp:49
void reset()
Reset the model.
Definition: seirconnected.hpp:114
Model< TSeq > * clone_ptr()
Advanced usage: Makes a copy of data and returns it as undeleted pointer.
Definition: seirconnected.hpp:125
ModelSEIRCONN< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: seirconnected.hpp:387
ModelSEIRCONN< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Runs the simulation (after initialization)
Definition: seirconnected.hpp:101
Definition: seirdconnected.hpp:6
ModelSEIRDCONN< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set up the initial states of the model.
Definition: seirdconnected.hpp:405
Definition: seirmixing.hpp:27
void reset()
Reset the model.
Definition: seirmixing.hpp:248
ModelSEIRMixing< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: seirmixing.hpp:596
ModelSEIRMixing< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Runs the simulation (after initialization)
Definition: seirmixing.hpp:235
Model< TSeq > * clone_ptr()
Advanced usage: Makes a copy of data and returns it as undeleted pointer.
Definition: seirmixing.hpp:334
SEIR model with mixing, quarantine, and contact tracing.
Definition: seirmixingquarantine.hpp:66
ModelSEIRMixingQuarantine< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: seirmixingquarantine.hpp:1205
Model< TSeq > * clone_ptr()
Create a clone of this model.
Definition: seirmixingquarantine.hpp:593
ModelSEIRMixingQuarantine< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Run the model simulation.
Definition: seirmixingquarantine.hpp:448
void reset()
Reset the model to initial state.
Definition: seirmixingquarantine.hpp:461
ModelSIRCONN< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Runs the simulation (after initialization)
Definition: sirconnected.hpp:107
Model< TSeq > * clone_ptr()
Advanced usage: Makes a copy of data and returns it as undeleted pointer.
Definition: sirconnected.hpp:131
ModelSIRCONN< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: sirconnected.hpp:360
void reset()
Reset the model.
Definition: sirconnected.hpp:119
Definition: sirdconnected.hpp:6
Definition: sirmixing.hpp:24
ModelSIRMixing< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Runs the simulation (after initialization)
Definition: sirmixing.hpp:232
ModelSIRMixing< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: sirmixing.hpp:551
Model< TSeq > * clone_ptr()
Advanced usage: Makes a copy of data and returns it as undeleted pointer.
Definition: sirmixing.hpp:324
void reset()
Reset the model.
Definition: sirmixing.hpp:244
Definition: surveillance.hpp:5
std::vector< epiworld_double > days_latent_and_infectious
Vector of days spent in latent and infectious states A row-major matrix.
Definition: surveillance.hpp:24
Controls which agents are verified at each step.
Definition: queue-bones.hpp:16
Tools for defending the agent against the virus.
Definition: tool-bones.hpp:40
Set of Tools (const) (useful for iterators)
Definition: tools-bones.hpp:117
Set of tools (useful for building iterators)
Definition: tools-bones.hpp:18
Personalized data by the user.
Definition: userdata-bones.hpp:17
Virus.
Definition: virus-bones.hpp:41
Definition: epiworld.hpp:7034
Agent (agents)
Definition: epiworld.hpp:10908
int get_id() const
Id of the individual.
Definition: epiworld.hpp:22122
void rm_agent_by_virus(Model< TSeq > *model)
Agent removed by virus.
Definition: epiworld.hpp:22074
Class for tracing contacts between agents.
Definition: epiworld.hpp:23176
Statistical data about the process.
Definition: epiworld.hpp:3592
Definition: epiworld.hpp:17122
Template for a Global Event.
Definition: epiworld.hpp:8148
Core class of epiworld.
Definition: epiworld.hpp:8392
std::vector< Agent< TSeq > > & get_agents()
Returns a reference to the vector of agents.
Definition: epiworld.hpp:11714
void load_agents_entities_ties(const std::vector< int > &agents_ids, const std::vector< int > &entities_ids)
Associate agents-entities from data.
Definition: epiworld.hpp:12278
void rm_globalevent(size_t i)
Remove a global action by index.
Definition: epiworld.hpp:13824
std::vector< Viruses_const< TSeq > > get_agents_viruses() const
Returns a const vector with the viruses of the agents.
Definition: epiworld.hpp:11736
void set_agents_data(double *data_, size_t ncols_)
Set the agents data object.
Definition: epiworld.hpp:13909
void queuing_on()
Activates the queuing system (default.)
Definition: epiworld.hpp:13849
bool is_queuing_on() const
Query if the queuing system is on.
Definition: epiworld.hpp:13862
void run_multiple(epiworld_fast_uint ndays, epiworld_fast_uint nexperiments, int seed_=-1, std::function< void(size_t, Model< TSeq > *)> fun=make_save_run< TSeq >(), bool reset=true, bool verbose=true, int nthreads=1)
Definition: epiworld.hpp:12609
Queue< TSeq > & get_queue()
Retrieve the Queue object.
Definition: epiworld.hpp:13868
void set_name(std::string name)
Set the name object.
Definition: epiworld.hpp:13927
void load_agents_entities_ties(std::string fn, int skip)
Associate agents-entities from a file.
Definition: epiworld.hpp:12220
size_t get_n_tools() const
Number of tools in the model.
Definition: epiworld.hpp:12899
void add_globalevent(std::function< void(Model< TSeq > *)> fun, std::string name="A global action", int date=-99)
Set a global action.
Definition: epiworld.hpp:13750
void write_data(std::string fn_virus_info, std::string fn_virus_hist, std::string fn_tool_info, std::string fn_tool_hist, std::string fn_total_hist, std::string fn_transmission, std::string fn_transition, std::string fn_reproductive_number, std::string fn_generation_time) const
Wrapper of DataBase::write_data
Definition: epiworld.hpp:12975
void events_run()
Executes the stored action.
Definition: epiworld.hpp:11351
Model< TSeq > & queuing_off()
Deactivates the queuing system.
Definition: epiworld.hpp:13855
virtual void reset()
Reset the model.
Definition: epiworld.hpp:13094
std::vector< epiworld_fast_uint > get_agents_states() const
Returns a vector with the states of the agents.
Definition: epiworld.hpp:11726
void draw(DiagramType diagram_type=DiagramType::Mermaid, const std::string &fn_output="", bool self=false)
Draws a mermaid diagram of the model.
Definition: epiworld.hpp:14108
GlobalEvent< TSeq > & get_globalevent(size_t i)
Retrieve a global action by index.
Definition: epiworld.hpp:13790
int today() const
The current time of the model.
Definition: epiworld.hpp:12448
virtual Model< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Runs the simulation (after initialization)
Definition: epiworld.hpp:12498
size_t get_n_viruses() const
Number of viruses in the model.
Definition: epiworld.hpp:12894
void rm_globalevent(std::string name)
Remove a global action by name.
Definition: epiworld.hpp:13804
std::vector< Viruses< TSeq > > get_agents_viruses()
Returns a vector with the viruses of the agents.
Definition: epiworld.hpp:11749
void set_user_data(std::vector< std::string > names)
[@
Definition: epiworld.hpp:13726
GlobalEvent< TSeq > & get_globalevent(std::string name)
Retrieve a global action by name.
Definition: epiworld.hpp:13776
void events_add(Agent< TSeq > *agent_, VirusPtr< TSeq > virus_, ToolPtr< TSeq > tool_, Entity< TSeq > *entity_, epiworld_fast_int new_state_, epiworld_fast_int queue_, EventFun< TSeq > call_, int idx_agent_, int idx_object_)
Construct a new Event object.
Definition: epiworld.hpp:11300
virtual Model< TSeq > * clone_ptr()
Advanced usage: Makes a copy of data and returns it as undeleted pointer.
Definition: epiworld.hpp:11512
A simple progress bar.
Definition: epiworld.hpp:866
Controls which agents are verified at each step.
Definition: epiworld.hpp:8002
Tools for defending the agent against the virus.
Definition: epiworld.hpp:16263
Personalized data by the user.
Definition: epiworld.hpp:3108
Virus.
Definition: epiworld.hpp:10657
Measles model with population mixing, quarantine, and contact tracing.
Definition: epiworld.hpp:30946
void set_contact_matrix(std::vector< double > cmat)
Set the contact matrix for population mixing.
Definition: epiworld.hpp:31161
std::vector< bool > get_isolation_willingness() const
Get the isolation willingness for all agents.
Definition: epiworld.hpp:31198
std::vector< double > get_contact_matrix() const
Get the current contact matrix.
Definition: epiworld.hpp:31171
std::vector< bool > get_quarantine_willingness() const
Get the quarantine willingness for all agents.
Definition: epiworld.hpp:31189
std::vector< size_t > get_agent_quarantine_triggered() const
Get the quarantine trigger status for all agents.
Definition: epiworld.hpp:31180
Measles model with population mixing and risk-based quarantine strategies.
Definition: epiworld.hpp:32272
auto get_quarantine_willingness() const
Get the quarantine willingness for all agents.
Definition: epiworld.hpp:32539
void set_contact_matrix(std::vector< double > cmat)
Set the contact matrix for population mixing.
Definition: epiworld.hpp:32520
void reset()
Reset the model to initial state.
Definition: epiworld.hpp:33517
ModelMeaslesMixingRiskQuarantine< TSeq > & run(epiworld_fast_uint ndays, int seed=-1)
Run the model simulation.
Definition: epiworld.hpp:33507
ModelMeaslesMixingRiskQuarantine< TSeq > & initial_states(std::vector< double > proportions_, std::vector< int > queue_={})
Set the initial states of the model.
Definition: epiworld.hpp:33641
const auto & get_quarantine_risk_level() const
Get the risk level assigned to each agent for quarantine purposes.
Definition: epiworld.hpp:32557
auto get_days_quarantine_triggered() const
Get the total number of quarantines that have occurred.
Definition: epiworld.hpp:32567
Model< TSeq > * clone_ptr()
Create a clone of this model.
Definition: epiworld.hpp:33629
auto get_contact_matrix() const
Get the current contact matrix.
Definition: epiworld.hpp:32530
auto get_isolation_willingness() const
Get the isolation willingness for all agents.
Definition: epiworld.hpp:32548
Template for a Measles model with quarantine.
Definition: epiworld.hpp:28820
Definition: epiworld.hpp:25179
Definition: epiworld.hpp:26526
Definition: epiworld.hpp:27585
SEIR model with mixing, quarantine, and contact tracing.
Definition: epiworld.hpp:29701
std::vector< double > get_contact_matrix() const
Get the current contact matrix.
Definition: epiworld.hpp:29907
std::vector< bool > get_isolation_willingness() const
Get the isolation willingness for all agents.
Definition: epiworld.hpp:29934
std::vector< bool > get_quarantine_willingness() const
Get the quarantine willingness for all agents.
Definition: epiworld.hpp:29925
std::vector< size_t > get_agent_quarantine_triggered() const
Get the quarantine trigger status for all agents.
Definition: epiworld.hpp:29916
void set_contact_matrix(std::vector< double > cmat)
Set the contact matrix for population mixing.
Definition: epiworld.hpp:29897
Definition: epiworld.hpp:24738
Definition: epiworld.hpp:26169
Template for a Susceptible-Infected-Removed (SIR) model.
Definition: epiworld.hpp:26992
Definition: epiworld.hpp:28211
#define SAMPLE_FROM_PROBS(n, ans)
Macro to sample from a list of probabilities.
Definition: measlesmixingriskquarantine.hpp:26
Virus< TSeq > * sample_virus_single(Agent< TSeq > *p, Model< TSeq > *m)
Sample from neighbors pool of viruses (at most one)
Definition: epiworld.hpp:18274
std::function< Virus< TSeq > *(Agent< TSeq > *, Model< TSeq > *)> make_sample_virus_neighbors(std::vector< epiworld_fast_uint > exclude={})
Make a function to sample from neighbors.
Definition: epiworld.hpp:18106
Functions for sampling viruses.
Definition: agent-meat-virus-sampling.hpp:8